const express = require('express');
const cors = require('cors');
const fs = require('fs');
const path = require('path');
const multer = require('multer');
const session = require('express-session');
const crypto = require('crypto');
const https = require('https');
let mysql;
try {
    mysql = require('mysql2/promise');
} catch (error) {
    console.log('MySQL模块未安装或无法加载');
}

// 飞书机器人Webhook地址 - 从环境变量读取，增强安全性
const FEISHU_WEBHOOK_URL = process.env.FEISHU_WEBHOOK_URL || 'https://open.feishu.cn/open-apis/bot/v2/hook/b90643fb-78b2-4046-86ca-1698ce8ddf6c';

const app = express();
// 配置信任代理以支持反向代理后的 HTTPS
app.set('trust proxy', true);
// 从环境变量读取端口配置，如果没有设置则使用默认端口3000
const PORT = process.env.PORT || 3000;

// 生成北京时间（UTC+8）的函数 - 返回YYYY-MM-DD HH:mm:ss格式
function getBeijingTime() {
    const now = new Date();
    // 获取UTC时间戳并加上8小时
    const beijingTimestamp = now.getTime() + 8 * 60 * 60 * 1000;
    const beijingTime = new Date(beijingTimestamp);
    
    // 格式化日期时间为YYYY-MM-DD HH:mm:ss
    const year = beijingTime.getUTCFullYear();
    const month = String(beijingTime.getUTCMonth() + 1).padStart(2, '0');
    const day = String(beijingTime.getUTCDate()).padStart(2, '0');
    const hours = String(beijingTime.getUTCHours()).padStart(2, '0');
    const minutes = String(beijingTime.getUTCMinutes()).padStart(2, '0');
    const seconds = String(beijingTime.getUTCSeconds()).padStart(2, '0');
    
    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

// 配置会话中间件
app.use(session({
    secret: process.env.SESSION_SECRET || crypto.randomBytes(32).toString('hex'),
    resave: false,
    saveUninitialized: false,
    cookie: {
        maxAge: 7 * 24 * 60 * 60 * 1000, // 7天，与登录时设置保持一致
        secure: process.env.NODE_ENV === 'production', // 生产环境使用HTTPS
        httpOnly: true,
        sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax' // 开发环境使用lax，生产环境使用none以支持credentials
    }
}));

// 登录失败计数存储
let loginAttempts = {};
const MAX_LOGIN_ATTEMPTS = 5;
const LOCKOUT_DURATION = 15 * 60 * 1000; // 15分钟锁定

// 会话认证中间件 - 增强安全性
function ensureAuthenticated(req, res, next) {
    // 检查请求是否是API请求
    const isApiRequest = req.path.startsWith('/api/');
    
    // 检查会话是否存在
    if (!req.session || !req.session.user) {
        if (isApiRequest) {
            return res.status(401).json({ error: '未授权访问，请先登录' });
        }
        return res.redirect('/login');
    }
    
    // 检查会话是否过期（超过7天即使是记住我也强制重新登录）
    const sessionAge = Date.now() - req.session.user.timestamp;
    const MAX_SESSION_DURATION = 7 * 24 * 60 * 60 * 1000; // 7天
    
    if (sessionAge > MAX_SESSION_DURATION) {
        delete req.session.user;
        if (isApiRequest) {
            return res.status(401).json({ error: '会话已过期，请重新登录' });
        }
        return res.redirect('/login');
    }
    
    // 更新会话活动时间
    req.session.user.lastActivity = Date.now();
    
    return next();
}

// 数据库配置 - 从环境变量读取，增强安全性
let dbConfig = {
    host: process.env.DB_HOST || 'localhost',
    port: process.env.DB_PORT || 3306,
    user: process.env.DB_USER || 'tongfengqi',
    password: process.env.DB_PASSWORD || 'tongfengqi',
    database: process.env.DB_NAME || 'tongfengqi',
    charset: 'utf8mb4',
    waitForConnections: true,
    connectionLimit: 10,
    queueLimit: 0
};

let pool = null;
let useDatabase = false;
// 初始化全局变量，确保ID从1开始
let nextJobApplicationId = 1;

// 数据文件路径（作为后备方案）
const DATA_FILE = path.join(__dirname, 'data', 'contact_forms.json');
const JOBS_FILE = path.join(__dirname, 'data', 'job_applications.json');
const JOB_POSTINGS_FILE = path.join(__dirname, 'data', 'job_postings.json');
const SERVICES_FILE = path.join(__dirname, 'data', 'services.json');

// 确保数据目录存在
if (!fs.existsSync(path.join(__dirname, 'data'))) {
    fs.mkdirSync(path.join(__dirname, 'data'));
}

// 确保数据文件存在
if (!fs.existsSync(DATA_FILE)) {
    fs.writeFileSync(DATA_FILE, JSON.stringify([]));
}
if (!fs.existsSync(JOBS_FILE)) {
    fs.writeFileSync(JOBS_FILE, JSON.stringify([]));
}
// 确保岗位数据文件存在
if (!fs.existsSync(JOB_POSTINGS_FILE)) {
    // 为文件存储模式创建示例岗位数据
    const sampleJobPostings = [
        {
            id: 1,
            title: '高级GEO优化工程师',
            category: '技术岗位',
            location: '济南',
            salary: '25-35K/月',
            responsibilities: '1. 负责公司产品的地理位置服务优化和算法改进\n2. 设计并实现高精度的位置定位和匹配系统\n3. 与前端团队协作，优化位置数据的展示和交互体验\n4. 持续研究和应用新技术，提升GEO服务性能和准确性\n5. 分析用户行为数据，优化位置相关功能',
            requirements: '1. 本科及以上学历，计算机相关专业\n2. 3年以上GEO服务或相关领域工作经验\n3. 熟悉地理位置服务的核心技术和算法\n4. 具备扎实的编程基础，精通至少一种编程语言（Python/Java/JavaScript等）\n5. 良好的团队协作能力和沟通能力',
            highlights: '1. 年轻活力的团队，扁平的管理结构\n2. 提供具有竞争力的薪资和福利待遇\n3. 多元化的技术栈和学习机会\n4. 参与前沿技术的研究和应用',
            tech_stack: 'Python, JavaScript, GIS, 位置算法, 大数据分析',
            is_active: true,
            created_at: new Date().toISOString(),
            updated_at: new Date().toISOString()
        },
        {
            id: 2,
            title: 'SEO策略分析师',
            category: '营销岗位',
            location: '济南',
            salary: '15-25K/月',
            responsibilities: '1. 制定并执行公司网站的SEO优化策略\n2. 分析搜索引擎算法变化，及时调整优化方案\n3. 监控和分析网站流量、关键词排名等数据\n4. 与内容团队协作，优化网站内容质量\n5. 定期制作SEO分析报告，提供数据支持和优化建议',
            requirements: '1. 本科及以上学历，市场营销、计算机相关专业优先\n2. 2年以上SEO相关工作经验\n3. 熟悉主流搜索引擎的工作原理和优化规则\n4. 具备良好的数据分析能力和报告撰写能力\n5. 对数字营销和内容创作有浓厚兴趣',
            highlights: '1. 专业的营销团队，丰富的行业经验\n2. 提供持续的专业培训和成长机会\n3. 弹性工作时间和远程工作可能性\n4. 优秀的团队文化和工作氛围',
            tech_stack: 'SEO, SEM, 数据分析, 内容营销, Google Analytics',
            is_active: true,
            created_at: new Date().toISOString(),
            updated_at: new Date().toISOString()
        },
        {
            id: 3,
            title: '前端开发工程师',
            category: '技术岗位',
            location: '济南',
            salary: '20-30K/月',
            responsibilities: '1. 负责公司产品的前端开发和优化\n2. 与设计团队协作，实现精美的用户界面\n3. 与后端团队协作，完成数据交互和功能实现\n4. 持续优化用户体验和页面性能\n5. 参与前端技术栈的选择和技术架构的设计',
            requirements: '1. 本科及以上学历，计算机相关专业\n2. 2年以上前端开发工作经验\n3. 精通HTML5、CSS3、JavaScript等前端技术\n4. 熟悉主流前端框架（Vue/React/Angular等）\n5. 良好的代码风格和团队协作能力',
            highlights: '1. 前沿的技术栈和开发工具\n2. 充满创新精神的团队环境\n3. 具有竞争力的薪资和晋升空间\n4. 定期的技术分享和学习机会',
            tech_stack: 'Vue.js, React, TypeScript, Webpack, SCSS, Responsive Design',
            is_active: true,
            created_at: new Date().toISOString(),
            updated_at: new Date().toISOString()
        }
    ];
    fs.writeFileSync(JOB_POSTINGS_FILE, JSON.stringify(sampleJobPostings));
}
// 确保服务数据文件存在
if (!fs.existsSync(SERVICES_FILE)) {
    // 为文件存储模式创建示例服务数据
    const sampleServices = [
        {
            id: 1,
            title: 'GEO 生成式引擎优化',
            icon: 'fa-globe',
            iconColor: 'text-blue-700',
            iconBg: 'bg-gradient-to-br from-blue-50 to-blue-100',
            description: '通过深度技术与创新策略，帮助企业在数字世界中脱颖而出。我们专注于生成式引擎优化，确保您的品牌在AI搜索时代保持领先地位。',
            features: [
                'AI搜索算法深度优化',
                '品牌信息结构化处理',
                '智能内容语义增强',
                '数据驱动的持续优化'
            ],
            result: '客户自然流量增长189%',
            order: 1,
            is_active: true,
            created_at: new Date().toISOString(),
            updated_at: new Date().toISOString()
        },
        {
            id: 2,
            title: 'SEO 搜索引擎优化',
            icon: 'fa-search',
            iconColor: 'text-green-700',
            iconBg: 'bg-gradient-to-br from-green-50 to-green-100',
            description: '全面的搜索引擎优化服务，提升网站在传统搜索引擎中的可见度和排名。通过技术优化、内容策略和用户体验改进，获取高质量自然流量。',
            features: [
                '网站技术架构优化',
                '关键词策略规划',
                '内容质量提升',
                '用户体验优化'
            ],
            result: '核心关键词排名提升20+位',
            order: 2,
            is_active: true,
            created_at: new Date().toISOString(),
            updated_at: new Date().toISOString()
        },
        {
            id: 3,
            title: '智能内容策略服务',
            icon: 'fa-lightbulb-o',
            iconColor: 'text-yellow-600',
            iconBg: 'bg-gradient-to-br from-yellow-50 to-yellow-100',
            description: '创建符合AI理解模式的品牌内容，构建结构化知识体系，提升品牌信息在AI和传统搜索中的准确性、权威性和可见性。',
            features: [
                '行业知识图谱构建',
                'AI友好内容创作',
                '内容结构化处理',
                '多媒体内容优化'
            ],
            result: '内容转化率提升58%',
            order: 3,
            is_active: true,
            created_at: new Date().toISOString(),
            updated_at: new Date().toISOString()
        },
        {
            id: 4,
            title: '关键词策略规划',
            icon: 'fa-key',
            iconColor: 'text-purple-700',
            iconBg: 'bg-gradient-to-br from-purple-50 to-purple-100',
            description: '基于大数据分析的关键词研究与策略制定，帮助企业锁定最具商业价值的搜索词，精准触达目标受众，最大化营销效果。',
            features: [
                '商业价值关键词挖掘',
                '竞争分析与差距识别',
                '搜索意图分类研究',
                '关键词矩阵构建'
            ],
            result: '高价值关键词覆盖率提升65%',
            order: 4,
            is_active: true,
            created_at: new Date().toISOString(),
            updated_at: new Date().toISOString()
        },
        {
            id: 5,
            title: 'AI 搜索优化咨询',
            icon: 'fa-robot',
            iconColor: 'text-indigo-700',
            iconBg: 'bg-gradient-to-br from-indigo-50 to-indigo-100',
            description: '前瞻性的AI搜索优化战略咨询，帮助企业提前布局下一代搜索技术，建立长期竞争优势，在AI驱动的搜索时代保持领先。',
            features: [
                'AI搜索趋势分析',
                '品牌数字资产审计',
                '优化策略定制',
                '实施路径规划'
            ],
            result: '客户品牌认知度提升82%',
            order: 5,
            is_active: true,
            created_at: new Date().toISOString(),
            updated_at: new Date().toISOString()
        }
    ];
    fs.writeFileSync(SERVICES_FILE, JSON.stringify(sampleServices));
}

// 初始化数据库连接池初始化数据库连接 - 添加连接池健康检查和错误处理
// 已在文件开头定义JOB_POSTINGS_FILE变量

async function initDatabase() {
    try {
        if (!mysql) {
            console.log('MySQL模块不可用，使用文件存储');
            return;
        }
        
        // 创建数据库连接池
        pool = mysql.createPool(dbConfig);
        
        // 测试连接
        const connection = await pool.getConnection();
        console.log('成功连接到数据库');
        
        // 设置连接池事件监听
        pool.on('connection', (connection) => {
            console.log('获取到数据库连接');
        });
        
        pool.on('release', (connection) => {
            console.log('数据库连接已释放');
        });
        
        pool.on('enqueue', () => {
            console.log('等待数据库连接');
        });
        
        console.log('开始初始化数据库表...');
        
        // 创建contact_forms表（使用IF NOT EXISTS保留现有数据）
        await connection.execute(`
            CREATE TABLE IF NOT EXISTS contact_forms (
                id INT AUTO_INCREMENT PRIMARY KEY COMMENT '咨询ID',
                name VARCHAR(255) NOT NULL COMMENT '联系人姓名',
                company_name VARCHAR(255) COMMENT '公司名称',
                phone VARCHAR(50) COMMENT '联系电话',
                interested_service VARCHAR(255) COMMENT '感兴趣的服务',
                message TEXT COMMENT '咨询内容',
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
                is_processed TINYINT(1) DEFAULT 0 COMMENT '是否已处理'
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
        `);
        console.log('contact_forms表初始化完成（保留现有数据）');
        
        // 创建job_applications表（使用IF NOT EXISTS保留现有数据）
        await connection.execute(`
            CREATE TABLE IF NOT EXISTS job_applications (
                id BIGINT PRIMARY KEY COMMENT '申请ID',
                name VARCHAR(255) NOT NULL COMMENT '申请人姓名',
                email VARCHAR(255) NOT NULL COMMENT '申请人邮箱',
                phone VARCHAR(50) COMMENT '申请人电话',
                position_name VARCHAR(255) COMMENT '申请职位',
                work_experience VARCHAR(255) COMMENT '工作经验',
                message TEXT COMMENT '申请留言',
                serverFileName VARCHAR(255) COMMENT '简历文件名',
                fileContent LONGBLOB COMMENT '简历文件内容',
                fileType VARCHAR(100) COMMENT '文件MIME类型',
                created_at DATETIME COMMENT '申请时间',
                is_processed TINYINT(1) DEFAULT 0 COMMENT '是否已处理'
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
        `);
        
        // 创建job_postings表（使用IF NOT EXISTS保留现有数据）
        await connection.execute(`
            CREATE TABLE IF NOT EXISTS job_postings (
                id INT AUTO_INCREMENT PRIMARY KEY COMMENT '岗位ID',
                title VARCHAR(255) NOT NULL COMMENT '岗位名称',
                category VARCHAR(100) COMMENT '岗位类别',
                location VARCHAR(100) COMMENT '工作地点',
                salary VARCHAR(100) COMMENT '薪资范围',
                responsibilities TEXT COMMENT '岗位职责',
                requirements TEXT COMMENT '任职要求',
                highlights TEXT COMMENT '团队亮点',
                tech_stack TEXT COMMENT '技术栈',
                is_active TINYINT(1) DEFAULT 1 COMMENT '是否有效',
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
                updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
        `);
        console.log('job_postings表初始化完成（保留现有数据）');
        
        // 创建services表（使用IF NOT EXISTS保留现有数据）
        await connection.execute(`
            CREATE TABLE IF NOT EXISTS services (
                id INT AUTO_INCREMENT PRIMARY KEY COMMENT '服务ID',
                title VARCHAR(255) NOT NULL COMMENT '服务名称',
                icon VARCHAR(100) COMMENT '图标类名',
                iconColor VARCHAR(100) COMMENT '图标颜色',
                iconBg VARCHAR(255) COMMENT '图标背景',
                description TEXT COMMENT '服务描述',
                features JSON COMMENT '服务特点',
                result VARCHAR(255) COMMENT '服务成果',
                \`order\` INT DEFAULT 0 COMMENT '排序',
                is_active TINYINT(1) DEFAULT 1 COMMENT '是否有效',
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
                updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
        `);
        console.log('services表初始化完成（保留现有数据）');
        
        // 插入示例服务数据（如果表为空）
        const [servicesCount] = await connection.execute('SELECT COUNT(*) as count FROM services');
        if (servicesCount[0].count === 0) {
            await connection.execute(`
                INSERT INTO services (title, icon, iconColor, iconBg, description, features, result, \`order\`, is_active)
                VALUES 
                ('GEO 生成式引擎优化', 'fa-globe', 'text-blue-700', 'bg-gradient-to-br from-blue-50 to-blue-100', 
                '通过深度技术与创新策略，帮助企业在数字世界中脱颖而出。我们专注于生成式引擎优化，确保您的品牌在AI搜索时代保持领先地位。', 
                '["AI搜索算法深度优化", "品牌信息结构化处理", "智能内容语义增强", "数据驱动的持续优化"]', 
                '客户自然流量增长189%', 1, 1),
                ('SEO 搜索引擎优化', 'fa-search', 'text-green-700', 'bg-gradient-to-br from-green-50 to-green-100', 
                '全面的搜索引擎优化服务，提升网站在传统搜索引擎中的可见度和排名。通过技术优化、内容策略和用户体验改进，获取高质量自然流量。', 
                '["网站技术架构优化", "关键词策略规划", "内容质量提升", "用户体验优化"]', 
                '核心关键词排名提升20+位', 2, 1),
                ('智能内容策略服务', 'fa-lightbulb-o', 'text-yellow-600', 'bg-gradient-to-br from-yellow-50 to-yellow-100', 
                '创建符合AI理解模式的品牌内容，构建结构化知识体系，提升品牌信息在AI和传统搜索中的准确性、权威性和可见性。', 
                '["行业知识图谱构建", "AI友好内容创作", "内容结构化处理", "多媒体内容优化"]', 
                '内容转化率提升58%', 3, 1),
                ('关键词策略规划', 'fa-key', 'text-purple-700', 'bg-gradient-to-br from-purple-50 to-purple-100', 
                '基于大数据分析的关键词研究与策略制定，帮助企业锁定最具商业价值的搜索词，精准触达目标受众，最大化营销效果。', 
                '["商业价值关键词挖掘", "竞争分析与差距识别", "搜索意图分类研究", "关键词矩阵构建"]', 
                '高价值关键词覆盖率提升65%', 4, 1),
                ('AI 搜索优化咨询', 'fa-robot', 'text-indigo-700', 'bg-gradient-to-br from-indigo-50 to-indigo-100', 
                '前瞻性的AI搜索优化战略咨询，帮助企业提前布局下一代搜索技术，建立长期竞争优势，在AI驱动的搜索时代保持领先。', 
                '["AI搜索趋势分析", "品牌数字资产审计", "优化策略定制", "实施路径规划"]', 
                '客户品牌认知度提升82%', 5, 1)
            `);
            console.log('已插入示例服务数据');
        }
        
        // 插入示例岗位数据（如果表为空）
        const [countResult] = await connection.execute('SELECT COUNT(*) as count FROM job_postings');
        if (countResult[0].count === 0) {
            await connection.execute(`
                INSERT INTO job_postings (title, category, location, salary, responsibilities, requirements, highlights, tech_stack)
                VALUES 
                ('高级GEO优化工程师', '技术岗位', '济南', '25-35K/月', 
                '1. 负责公司产品的地理位置服务优化和算法改进\n2. 设计并实现高精度的位置定位和匹配系统\n3. 与前端团队协作，优化位置数据的展示和交互体验\n4. 持续研究和应用新技术，提升GEO服务性能和准确性\n5. 分析用户行为数据，优化位置相关功能', 
                '1. 本科及以上学历，计算机相关专业\n2. 3年以上GEO服务或相关领域工作经验\n3. 熟悉地理位置服务的核心技术和算法\n4. 具备扎实的编程基础，精通至少一种编程语言（Python/Java/JavaScript等）\n5. 良好的团队协作能力和沟通能力', 
                '1. 年轻活力的团队，扁平的管理结构\n2. 提供具有竞争力的薪资和福利待遇\n3. 多元化的技术栈和学习机会\n4. 参与前沿技术的研究和应用', 
                'Python, JavaScript, GIS, 位置算法, 大数据分析'),
                ('SEO策略分析师', '营销岗位', '济南', '15-25K/月', 
                '1. 制定并执行公司网站的SEO优化策略\n2. 分析搜索引擎算法变化，及时调整优化方案\n3. 监控和分析网站流量、关键词排名等数据\n4. 与内容团队协作，优化网站内容质量\n5. 定期制作SEO分析报告，提供数据支持和优化建议', 
                '1. 本科及以上学历，市场营销、计算机相关专业优先\n2. 2年以上SEO相关工作经验\n3. 熟悉主流搜索引擎的工作原理和优化规则\n4. 具备良好的数据分析能力和报告撰写能力\n5. 对数字营销和内容创作有浓厚兴趣', 
                '1. 专业的营销团队，丰富的行业经验\n2. 提供持续的专业培训和成长机会\n3. 弹性工作时间和远程工作可能性\n4. 优秀的团队文化和工作氛围', 
                'SEO, SEM, 数据分析, 内容营销, Google Analytics'),
                ('前端开发工程师', '技术岗位', '济南', '20-30K/月', 
                '1. 负责公司产品的前端开发和优化\n2. 与设计团队协作，实现精美的用户界面\n3. 与后端团队协作，完成数据交互和功能实现\n4. 持续优化用户体验和页面性能\n5. 参与前端技术栈的选择和技术架构的设计', 
                '1. 本科及以上学历，计算机相关专业\n2. 2年以上前端开发工作经验\n3. 精通HTML5、CSS3、JavaScript等前端技术\n4. 熟悉主流前端框架（Vue/React/Angular等）\n5. 良好的代码风格和团队协作能力', 
                '1. 前沿的技术栈和开发工具\n2. 充满创新精神的团队环境\n3. 具有竞争力的薪资和晋升空间\n4. 定期的技术分享和学习机会', 
                'Vue.js, React, TypeScript, Webpack, SCSS, Responsive Design')
            `);
            console.log('已插入示例岗位数据');
        }
        
        // 检查并添加created_at字段（使用替代方法）
        try {
            // 首先尝试查询字段
            const [fields] = await connection.execute(
                "SHOW COLUMNS FROM job_applications LIKE 'created_at'"
            );
            
            // 如果字段不存在，则添加
            if (!fields || fields.length === 0) {
                await connection.execute(`
                    ALTER TABLE job_applications 
                    ADD COLUMN created_at DATETIME COMMENT '申请时间'
                `);
                console.log('添加了缺失的created_at字段');
            } else {
                console.log('created_at字段已存在');
            }
        } catch (err) {
            console.error('处理created_at字段时出错:', err);
        }
        
        // 检查并删除多余的createdAt列（如果存在）
        try {
            const [fields] = await connection.execute(
                "SHOW COLUMNS FROM job_applications LIKE 'createdAt'"
            );
            
            // 如果字段存在，则删除
            if (fields && fields.length > 0) {
                await connection.execute(
                    "ALTER TABLE job_applications DROP COLUMN createdAt"
                );
                console.log('删除了多余的createdAt字段');
            }
        } catch (err) {
            console.error('处理createdAt字段时出错:', err);
        }
        
        // 检查并添加is_processed字段（如果不存在）
        try {
            const [fields] = await connection.execute(
                "SHOW COLUMNS FROM job_applications LIKE 'is_processed'"
            );
            
            // 如果字段不存在，则添加
            if (!fields || fields.length === 0) {
                await connection.execute(`
                    ALTER TABLE job_applications 
                    ADD COLUMN is_processed TINYINT(1) DEFAULT 0 COMMENT '是否已处理'
                `);
                console.log('添加了缺失的is_processed字段');
            } else {
                console.log('is_processed字段已存在');
            }
        } catch (err) {
            console.error('处理is_processed字段时出错:', err);
        }
        
        // 检查并添加serverFileName字段（如果不存在）
        try {
            const [fields] = await connection.execute(
                "SHOW COLUMNS FROM job_applications LIKE 'serverFileName'"
            );
            
            // 如果字段不存在，则添加
            if (!fields || fields.length === 0) {
                await connection.execute(`
                    ALTER TABLE job_applications 
                    ADD COLUMN serverFileName VARCHAR(255) COMMENT '服务器存储的简历文件名'
                `);
                console.log('添加了缺失的serverFileName字段');
            } else {
                console.log('serverFileName字段已存在');
            }
        } catch (err) {
            console.error('处理serverFileName字段时出错:', err);
        }
        
        // 检查并添加fileContent字段（如果不存在）
        try {
            const [fields] = await connection.execute(
                "SHOW COLUMNS FROM job_applications LIKE 'fileContent'"
            );
            
            // 如果字段不存在，则添加
            if (!fields || fields.length === 0) {
                await connection.execute(`
                    ALTER TABLE job_applications 
                    ADD COLUMN fileContent LONGBLOB COMMENT '简历文件二进制内容'
                `);
                console.log('添加了缺失的fileContent字段');
            } else {
                console.log('fileContent字段已存在');
            }
        } catch (err) {
            console.error('处理fileContent字段时出错:', err);
        }
        
        // 检查并添加fileType字段（如果不存在）
        try {
            const [fields] = await connection.execute(
                "SHOW COLUMNS FROM job_applications LIKE 'fileType'"
            );
            
            // 如果字段不存在，则添加
            if (!fields || fields.length === 0) {
                await connection.execute(`
                    ALTER TABLE job_applications 
                    ADD COLUMN fileType VARCHAR(100) COMMENT '文件MIME类型'
                `);
                console.log('添加了缺失的fileType字段');
            } else {
                console.log('fileType字段已存在');
            }
        } catch (err) {
            console.error('处理fileType字段时出错:', err);
        }
        
        // 检查并删除多余的originalResumeName列（如果存在）
        try {
            const [fields] = await connection.execute(
                "SHOW COLUMNS FROM job_applications LIKE 'originalResumeName'"
            );
            
            // 如果字段存在，则删除
            if (fields && fields.length > 0) {
                await connection.execute(
                    "ALTER TABLE job_applications DROP COLUMN originalResumeName"
                );
                console.log('删除了多余的originalResumeName字段');
            } else {
                console.log('originalResumeName字段不存在');
            }
        } catch (err) {
            console.error('处理originalResumeName字段时出错:', err);
        }
        console.log('job_applications表初始化完成（保留现有数据）');
        
        // 查询数据库中已有的最大ID，确保正确生成下一个ID
        try {
            // 先查询数据库中的最大ID
            const [maxIdResults] = await connection.query('SELECT MAX(id) as maxId FROM job_applications');
            const maxId = maxIdResults && maxIdResults[0] && maxIdResults[0].maxId ? maxIdResults[0].maxId : 0;
            
            // 设置nextJobApplicationId为maxId + 1
            nextJobApplicationId = maxId + 1;
            
            // 查询数据库中是否有记录
            const [countResults] = await connection.query('SELECT COUNT(*) as count FROM job_applications');
            const recordCount = countResults && countResults[0] ? countResults[0].count : 0;
            
            console.log(`数据库中有记录: ${recordCount} 条，最大ID为: ${maxId}，下次将使用ID: ${nextJobApplicationId}`);
        } catch (err) {
            console.error('初始化ID时出错:', err);
            // 出错时使用默认ID值1
            nextJobApplicationId = 1;
            console.log('使用默认ID值: 1');
        }
        
        console.log('数据库表初始化成功，将使用数据库存储');
        useDatabase = true;
        connection.release();
    } catch (error) {
        console.error('数据库初始化失败，使用文件存储作为后备方案:', error);
        useDatabase = false;
    }
}

// 中间件 - 配置CORS以支持生产环境
// 健康检查接口
app.get('/api/health', (req, res) => {
    res.status(200).json({ status: 'ok', timestamp: getBeijingTime(), message: '后端服务正常运行' });
});

app.use(cors({
    origin: function(origin, callback) {
        // 允许localhost的所有端口、服务器公网地址或特定环境配置的origin
        if (!origin || /^http:\/\/localhost:\d+$/.test(origin) || /^http:\/\/101\.201\.52\.105$/.test(origin) || /^http:\/\/101\.201\.52\.105:\d+$/.test(origin)) {
            callback(null, true);
        } else {
            console.log('CORS错误：不允许的源', origin);
            callback(new Error('不允许的跨域请求'));
        }
    },
    credentials: true,
    methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
    allowedHeaders: ['Content-Type', 'Authorization']
}));

// 请求日志中间件
app.use((req, res, next) => {
    console.log(`${new Date().toISOString()} - ${req.method} ${req.path}`);
    next();
});

// 会话劫持检测中间件
app.use((req, res, next) => {
    // 只有已登录用户才需要进行检测
    if (req.session && req.session.user) {
        const clientIP = req.ip || req.connection.remoteAddress;
        const userAgent = req.headers['user-agent'];
        
        // 检查IP地址是否变更
        if (req.session.user.ipAddress !== clientIP) {
            console.warn(`会话IP变更检测: 从 ${req.session.user.ipAddress} 到 ${clientIP}`);
        }
        
        // 检查User-Agent是否变更
        if (req.session.user.userAgent !== userAgent) {
            console.warn('会话User-Agent变更检测');
        }
    }
    next();
});

// 添加错误处理中间件
app.use(express.json());

app.use((err, req, res, next) => {
    console.error('未捕获的错误:', err);
    res.status(500).json({ error: '服务器内部错误' });
});

// 配置multer使用内存存储而不是磁盘存储
const upload = multer({
    storage: multer.memoryStorage(),
    limits: {
        fileSize: 5 * 1024 * 1024, // 限制文件大小为5MB
        files: 1 // 限制只能上传一个文件
    },
    fileFilter: function(req, file, cb) {
        // 二次验证文件类型
        const allowedTypes = ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'];
        if (allowedTypes.includes(file.mimetype)) {
            cb(null, true);
        } else {
            cb(new Error('不支持的文件类型'));
        }
    }
});

// 增强Express的req.body解析，确保中文内容正确编码
app.use((req, res, next) => {
    if (req.headers['content-type'] && req.headers['content-type'].includes('multipart/form-data')) {
        // multer已经处理了multipart/form-data，这里只需要确保处理正确
        next();
    } else {
        // 对于其他内容类型，确保编码正确
        express.json({ limit: '50mb' })(req, res, next);
    }
});

// 获取所有联系表单
app.get('/api/contact-forms', async (req, res) => {
    try {
        if (useDatabase && pool) {
            const [rows] = await pool.execute('SELECT * FROM contact_forms ORDER BY created_at DESC');
            res.json(rows);
        } else {
            // 使用文件存储作为后备方案
            const data = JSON.parse(fs.readFileSync(DATA_FILE, 'utf8'));
            res.json(data);
        }
    } catch (error) {
        console.error('读取数据失败:', error);
        res.status(500).json({ error: '读取数据失败' });
    }
});

// 提交联系表单
app.post('/api/contact-forms', async (req, res) => {
    try {
        // 确保所有字段都不为undefined
        const name = req.body.name ?? '';
        const company_name = req.body.company_name ?? null;
        const phone = req.body.phone ?? null;
        const interested_service = req.body.interested_service ?? null;
        const message = req.body.message ?? null;
        // 使用北京时间（UTC+8），格式为YYYY-MM-DD HH:mm:ss
        const created_at = getBeijingTime();
        
        const newForm = {
            name,
            company_name,
            phone,
            interested_service,
            message,
            created_at,
            is_processed: false
        };
        
        if (useDatabase && pool) {
            // 尝试使用数据库存储
            // 确保传递给数据库的参数都不为undefined
            // 将ISO格式的时间转换为MySQL时间格式
            // 直接使用格式化后的时间字符串，已经是MySQL兼容的格式
            const dbCreatedAt = created_at;
            await pool.execute(
                'INSERT INTO contact_forms (name, company_name, phone, interested_service, message, created_at) VALUES (?, ?, ?, ?, ?, ?)',
                [name, company_name, phone, interested_service, message, dbCreatedAt]
            );
            console.log('数据已保存到数据库');
        } else {
            // 使用文件存储作为后备方案
            const data = JSON.parse(fs.readFileSync(DATA_FILE, 'utf8'));
            data.push(newForm);
            fs.writeFileSync(DATA_FILE, JSON.stringify(data, null, 2));
            console.log('数据已保存到文件');
        }
        
        // 发送消息到飞书机器人
        const feishuContent = `有新的咨询信息！\n\n联系人：${name}\n公司名称：${company_name || '未提供'}\n联系电话：${phone || '未提供'}\n感兴趣的服务：${interested_service || '未指定'}\n咨询内容：${message || '无'}\n提交时间：${newForm.created_at}`;
        
        // 异步发送消息，不影响主流程
        sendToFeishu('【新咨询消息】', feishuContent).catch(err => {
            console.error('发送飞书通知失败，但不影响咨询处理:', err);
        });
        
        res.status(201).json({ success: true, data: newForm });
    } catch (error) {
        console.error('保存数据失败:', error);
        res.status(500).json({ error: '保存数据失败' });
    }
});

// 提交职位申请 - 使用multer处理multipart/form-data
app.post('/api/job-application', upload.any(), async (req, res) => {
    try {
        // FormData提交时，字段在req.body中，文件在req.files中
        const id = nextJobApplicationId; // 使用递增的ID
        nextJobApplicationId++; // 递增ID，确保下次申请使用新ID
        // 使用北京时间（UTC+8），格式为YYYY-MM-DD HH:mm:ss
        const created_at = getBeijingTime();
        
        // 增强输入验证
        const name = (req.body.name || '').trim();
        const email = (req.body.email || '').trim();
        const phone = (req.body.phone || '').trim();
        const position_name = (req.body.position || '').trim();
        
        // 必填字段验证
        if (!name || !email || !position_name) {
            return res.status(400).json({ success: false, error: '姓名、邮箱和申请职位为必填项' });
        }
        
        // 防止过长的输入
        if (name.length > 100 || email.length > 255 || position_name.length > 200) {
            return res.status(400).json({ success: false, error: '输入内容过长' });
        }
        
        // 邮箱格式验证
        const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
        if (!emailRegex.test(email)) {
            return res.status(400).json({ success: false, error: '邮箱格式不正确' });
        }
        
        // 手机号格式验证（如果提供了手机号）
        if (phone) {
            const phoneRegex = /^1[3-9]\d{9}$/;
            if (!phoneRegex.test(phone)) {
                return res.status(400).json({ success: false, error: '手机号格式不正确' });
            }
        }
        
        // 提取其他可选字段，进行安全处理
        const work_experience = (req.body.experience || '').trim() || null;
        const message = (req.body.message || '').trim() || null;
        
        // 限制可选字段长度
        if (work_experience && work_experience.length > 500) {
            return res.status(400).json({ success: false, error: '工作经验描述过长' });
        }
        if (message && message.length > 1000) {
            return res.status(400).json({ success: false, error: '留言内容过长' });
        }
        
        // 安全地处理上传文件
        let serverFileName = null;
        let fileContent = null;
        let fileType = null;
        
        if (req.files && req.files.length > 0) {
            const file = req.files[0];
            // 验证文件类型，防止恶意文件上传
            const allowedTypes = ['.pdf', '.doc', '.docx'];
            const fileExt = path.extname(file.originalname).toLowerCase();
            if (!allowedTypes.includes(fileExt)) {
                return res.status(400).json({ success: false, error: '不支持的文件类型，请上传PDF或Word文档' });
            }
            
            // 生成安全的文件名
            const name = (req.body.name || '未知姓名').toString().normalize('NFC');
            const position = (req.body.position || '未知岗位').toString().normalize('NFC');
            const phone = (req.body.phone || '未知电话').toString().normalize('NFC');
            
            // 移除所有特殊字符，只保留安全字符
            let safeName = name.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '_');
            let safePosition = position.replace(/[^a-zA-Z0-9\u4e00-\u9fa5]/g, '_');
            let safePhone = phone.replace(/[^0-9]/g, '');
            
            // 限制字符串长度
            safeName = safeName.substring(0, 20);
            safePosition = safePosition.substring(0, 30);
            safePhone = safePhone.substring(0, 11);
            
            // 生成安全的文件名
            serverFileName = `${safeName}-${safePosition}-${safePhone}${fileExt}`;
            
            // 从内存中获取文件内容和类型
            fileContent = file.buffer;
            fileType = file.mimetype;
            
            // 添加详细日志，记录文件信息
            console.log('保存简历文件到数据库:', serverFileName);
            console.log('文件大小:', file.buffer.length, '字节');
            console.log('文件类型:', file.mimetype);
            console.log('文件内容是否为Buffer:', Buffer.isBuffer(fileContent));
            console.log('文件内容前10个字节:', fileContent.slice(0, 10).toString('hex')); // 记录文件头部以验证内容
        }
        
        const application = {
            id,
            name,
            email,
            phone: phone || null,
            position_name,
            work_experience,
            message,
            serverFileName,
            created_at
        };
        
        console.log('使用递增ID:', id);
        console.log('收到职位申请:', application);
        
        // 安全地保存数据
        try {
            if (useDatabase && pool) {
                // 尝试使用数据库存储，包含简历文件二进制内容
                console.log('准备插入数据库，包含fileContent和fileType字段');
                // 检查fileContent和fileType是否正确设置
                console.log('插入前检查 - fileContent类型:', fileContent ? typeof fileContent : 'null');
                console.log('插入前检查 - fileContent是否为Buffer:', fileContent ? Buffer.isBuffer(fileContent) : false);
                console.log('插入前检查 - fileContent大小:', fileContent ? fileContent.length : 'null', '字节');
                console.log('插入前检查 - fileType:', fileType);
                
                // 确保fileContent是Buffer类型
                let finalFileContent = fileContent;
                if (fileContent && !Buffer.isBuffer(fileContent)) {
                    console.warn('文件内容不是Buffer类型，尝试转换...');
                    try {
                        if (typeof fileContent === 'string') {
                            finalFileContent = Buffer.from(fileContent);
                        } else {
                            finalFileContent = Buffer.from(JSON.stringify(fileContent));
                        }
                        console.log('转换后文件内容大小:', finalFileContent.length, '字节');
                    } catch (convertError) {
                        console.error('转换文件内容为Buffer失败:', convertError);
                        finalFileContent = null;
                    }
                }
                
                // 添加数据插入前的最后验证
                if (finalFileContent && finalFileContent.length > 0) {
                    console.log('准备插入有效文件内容，大小:', finalFileContent.length, '字节');
                } else if (serverFileName) {
                    console.warn('serverFileName存在但fileContent为空，将保存记录但不包含文件内容');
                }
                
                // 始终保存文件到文件系统作为备份，无论数据库操作是否成功
                if (serverFileName && finalFileContent && finalFileContent.length > 0) {
                    console.log('准备保存文件到文件系统作为强制备份');
                    // 移除文件系统保存功能，仅使用数据库存储
                    console.log(`简历文件内容已准备好存储到数据库，大小: ${finalFileContent.length} 字节`);
                    // 不再将简历文件保存到文件系统，以保护用户隐私
                }
                
                const [result] = await pool.execute(
                    'INSERT INTO job_applications (id, name, email, phone, position_name, work_experience, message, serverFileName, fileContent, fileType, created_at, is_processed) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
                    [id, name, email, phone || null, position_name, work_experience, message, serverFileName, finalFileContent, fileType, created_at, 0]
                );
                console.log('职位申请已保存到数据库，受影响行数:', result.affectedRows);
                
                // 移除立即验证以提高性能
                console.log('职位申请已保存到数据库');
            } else {
                // 使用文件存储作为后备方案
                // 使用同步操作确保数据完整性
                const jobsData = JSON.parse(fs.readFileSync(JOBS_FILE, 'utf8'));
                // 添加is_processed字段
                application.is_processed = 0;
                jobsData.push(application);
                fs.writeFileSync(JOBS_FILE, JSON.stringify(jobsData, null, 2));
                console.log('职位申请已保存到文件');
            }
        } catch (storageError) {
            console.error('保存职位申请数据时出错:', storageError);
            // 使用内存存储，无需删除文件系统中的文件
            console.log('保存失败，内存中的文件数据将自动被垃圾回收');
            throw storageError;
        }
        
        // 准备发送到飞书的内容，防止XSS攻击
        const safeName = name.replace(/[<>"']/g, '');
        const safeEmail = email.replace(/[<>"']/g, '');
        const safePosition = position_name.replace(/[<>"']/g, '');
        
        const feishuContent = `有新的职位申请信息！

申请人：${safeName}
邮箱：${safeEmail}
电话：${phone || '未提供'}
申请职位：${safePosition}
工作经验：${work_experience || '未提供'}
申请留言：${message || '无'}
申请时间：${created_at}

简历同步至同风起简历管理系统`;
        
        // 异步发送消息，不影响主流程
        sendToFeishu('【新职位申请】', feishuContent).catch(err => {
            console.error('发送飞书通知失败，但不影响申请处理:', err);
        });
        
        res.status(201).json({ success: true, data: application });
    } catch (error) {
        console.error('保存职位申请失败:', error);
        // 根据错误类型返回更具体的错误信息
        if (error.code === 'ECONNREFUSED' || error.code === 'ETIMEDOUT') {
            res.status(503).json({ success: false, error: '服务暂时不可用，请稍后重试' });
        } else if (error.code === 'EACCES' || error.code === 'ENOENT') {
            res.status(500).json({ success: false, error: '服务器存储错误' });
        } else {
            res.status(500).json({ success: false, error: '保存申请失败' });
        }
    }
});

// 获取职位申请列表 - 支持分页优化
app.get('/api/job-applications', async (req, res) => {
    try {
        // 获取分页参数，设置默认值并确保是数字类型，最多每页10条数据
        const page = Number(req.query.page) || 1;
        const limit = Math.min(Number(req.query.limit) || 10, 10); // 默认每页10条，最多10条数据
        const offset = (page - 1) * limit;
        
        // 记录开始时间用于性能监控
        const startTime = Date.now();
        
        if (useDatabase && pool) {
            // 优化1: 只选择必要的字段，而不是使用SELECT *
            // 优化2: 添加分页查询
            const countQuery = 'SELECT COUNT(*) as total FROM job_applications';
            // 直接在SQL语句中插入数字，避免参数类型问题
            const dataQuery = `SELECT id, name, email, phone, position_name, work_experience, created_at, is_processed, serverFileName, message 
                              FROM job_applications ORDER BY id DESC LIMIT ${Number(limit)} OFFSET ${Number(offset)}`;
            
            console.log(`执行分页查询: page=${page}, limit=${limit}, offset=${offset}`);
            
            // 并行执行计数和数据查询
            const [countResult] = await pool.execute(countQuery);
            const [rows] = await pool.execute(dataQuery);
            
            const total = countResult[0].total;
            const totalPages = Math.ceil(total / limit);
            
            // 记录查询耗时
            console.log(`数据库查询耗时: ${Date.now() - startTime}ms, 返回${rows.length}条记录`);
            
            // 返回分页数据和元信息
            res.status(200).json({
                data: rows,
                pagination: {
                    total,
                    page,
                    limit,
                    totalPages
                }
            });
        } else {
            // 文件存储也实现分页
            const jobsData = JSON.parse(fs.readFileSync(JOBS_FILE, 'utf8'));
            // 按ID降序排序
            jobsData.sort((a, b) => b.id - a.id);
            
            // 计算分页数据
            const total = jobsData.length;
            const paginatedData = jobsData.slice(offset, offset + limit);
            const totalPages = Math.ceil(total / limit);
            
            // 记录查询耗时
            console.log(`文件查询耗时: ${Date.now() - startTime}ms, 返回${paginatedData.length}条记录`);
            
            // 返回分页数据和元信息
            res.status(200).json({
                data: paginatedData,
                pagination: {
                    total,
                    page,
                    limit,
                    totalPages
                }
            });
        }
    } catch (error) {
        console.error('获取职位申请列表失败:', error);
        // 添加更详细的错误信息，包括SQL状态和错误代码
        console.error('SQL错误详情:', { 
            sqlState: error.sqlState, 
            errno: error.errno, 
            code: error.code 
        });
        res.status(500).json({ 
            error: '获取职位申请列表失败',
            details: error.message,
            sqlState: error.sqlState,
            errno: error.errno
        });
    }
});

// 删除职位申请的API - 支持自动重排ID
app.delete('/api/job-applications/:id', ensureAuthenticated, async (req, res) => {
    try {
        const { id } = req.params;
        const deleteId = parseInt(id);
        
        if (isNaN(deleteId)) {
            return res.status(400).json({ error: '无效的ID' });
        }
        
        if (useDatabase && pool) {
            // 使用数据库删除并重新编号
            
            // 1. 获取要删除的记录的serverFileName（如果有）
            const [records] = await pool.execute(
                'SELECT serverFileName FROM job_applications WHERE id = ?',
                [deleteId]
            );
            
            // 2. 删除记录
            const [deleteResult] = await pool.execute(
                'DELETE FROM job_applications WHERE id = ?',
                [deleteId]
            );
            
            if (deleteResult.affectedRows === 0) {
                return res.status(404).json({ error: '未找到对应的职位申请' });
            }
            
            // 文件内容存储在数据库中，无需从文件系统删除文件
            console.log('已从数据库删除申请记录，文件内容自动随记录删除');
            
            // 4. 重新编号所有大于删除ID的记录
            await pool.execute(
                'UPDATE job_applications SET id = id - 1 WHERE id > ? ORDER BY id',
                [deleteId]
            );
            
            // 5. 更新最大ID值
            const [maxIdResult] = await pool.execute('SELECT MAX(id) as maxId FROM job_applications');
            const newMaxId = maxIdResult[0].maxId || 0;
            await pool.execute('UPDATE app_state SET value = ? WHERE key = ?', [newMaxId, 'max_job_application_id']);
            
            console.log(`成功删除职位申请ID: ${deleteId}，并重新编号`);
            // 确保返回正确的状态码和JSON格式响应
            return res.status(200).json({ success: true, message: '职位申请已删除，ID已自动重新编号' });
        } else {
            // 使用文件存储删除并重新编号
            const jobsData = JSON.parse(fs.readFileSync(JOBS_FILE, 'utf8'));
            
            // 查找要删除的记录索引
            const index = jobsData.findIndex(job => job.id === deleteId);
            
            if (index === -1) {
                return res.status(404).json({ error: '未找到对应的职位申请' });
            }
            
            // 获取要删除的记录的serverFileName（如果有）
            const serverFileName = jobsData[index].serverFileName;
            
            // 删除记录
            jobsData.splice(index, 1);
            
            // 文件内容存储在数据库中，无需从文件系统删除文件
            console.log('已删除申请记录，文件内容处理由数据库管理');
            
            // 重新编号所有记录
            for (let i = 0; i < jobsData.length; i++) {
                jobsData[i].id = i + 1;
            }
            
            // 写回文件
            fs.writeFileSync(JOBS_FILE, JSON.stringify(jobsData, null, 2));
            
            console.log(`成功删除职位申请ID: ${deleteId}，并重新编号`);
            res.status(200).json({ success: true, message: '职位申请已删除，ID已自动重新编号' });
        }
    } catch (error) {
        console.error('删除职位申请失败:', error);
        res.status(500).json({ error: '删除职位申请失败', details: error.message });
    }
});

// 更新职位申请处理状态的API
app.put('/api/job-applications/:id', ensureAuthenticated, async (req, res) => {
    try {
        const { id } = req.params;
        const { is_processed } = req.body;
        
        // 验证输入
        if (typeof is_processed !== 'boolean') {
            return res.status(400).json({ error: '无效的处理状态' });
        }
        
        if (useDatabase && pool) {
            // 使用数据库更新
            const [result] = await pool.execute(
                'UPDATE job_applications SET is_processed = ? WHERE id = ?',
                [is_processed ? 1 : 0, id]
            );
            
            if (result.affectedRows === 0) {
                return res.status(404).json({ error: '未找到对应的职位申请' });
            }
            
            res.status(200).json({ success: true, message: '处理状态已更新' });
        } else {
            // 使用文件存储更新
            const jobsData = JSON.parse(fs.readFileSync(JOBS_FILE, 'utf8'));
            const jobIndex = jobsData.findIndex(job => job.id === parseInt(id));
            
            if (jobIndex === -1) {
                return res.status(404).json({ error: '未找到对应的职位申请' });
            }
            
            jobsData[jobIndex].is_processed = is_processed ? 1 : 0;
            fs.writeFileSync(JOBS_FILE, JSON.stringify(jobsData, null, 2));
            
            res.status(200).json({ success: true, message: '处理状态已更新' });
        }
    } catch (error) {
        console.error('更新处理状态失败:', error);
        res.status(500).json({ error: '更新处理状态失败' });
    }
});

// 登录API - 增强安全性，添加失败次数限制和密码验证
app.post('/api/login', (req, res) => {
    try {
        const { username, password, remember } = req.body;
        const clientIP = req.ip || req.connection.remoteAddress;
        
        // 输入验证
        if (!username || !password) {
            return res.status(400).json({ success: false, message: '请输入用户名和密码' });
        }
        
        // 检查登录尝试次数
        if (loginAttempts[clientIP] && loginAttempts[clientIP].count >= MAX_LOGIN_ATTEMPTS) {
            const timeSinceLastAttempt = Date.now() - loginAttempts[clientIP].lastAttempt;
            if (timeSinceLastAttempt < LOCKOUT_DURATION) {
                const remainingTime = Math.ceil((LOCKOUT_DURATION - timeSinceLastAttempt) / 60000);
                return res.status(429).json({ 
                    success: false, 
                    message: `登录尝试次数过多，请${remainingTime}分钟后再试` 
                });
            } else {
                // 重置锁定计数
                loginAttempts[clientIP] = { count: 0, lastAttempt: Date.now() };
            }
        }
        
        // 获取有效的用户名和密码（从环境变量或使用默认值）
        const validUsername = process.env.ADMIN_USERNAME || 'admin';
        const validPassword = process.env.ADMIN_PASSWORD || 'admin123';
        
        // 验证凭据
        if (username === validUsername && password === validPassword) {
            // 重置登录失败计数
            delete loginAttempts[clientIP];
            
            // 设置会话
            req.session.user = {
                username: username,
                loggedIn: true,
                timestamp: new Date().getTime(),
                lastActivity: new Date().getTime(),
                userAgent: req.headers['user-agent'],
                ipAddress: clientIP
            };
            
            // 如果勾选了记住我，延长会话时间
            if (remember) {
                req.session.cookie.maxAge = 7 * 24 * 60 * 60 * 1000; // 7天
            }
            
            // 记录登录成功
            console.log(`用户登录成功: ${username} - IP: ${clientIP}`);
            
            // 登录成功
            res.json({ success: true, message: '登录成功' });
        } else {
            // 记录登录失败
            if (!loginAttempts[clientIP]) {
                loginAttempts[clientIP] = { count: 0, lastAttempt: Date.now() };
            }
            loginAttempts[clientIP].count++;
            loginAttempts[clientIP].lastAttempt = Date.now();
            
            const remainingAttempts = Math.max(0, MAX_LOGIN_ATTEMPTS - loginAttempts[clientIP].count);
            console.warn(`登录失败: 用户名或密码错误 - IP: ${clientIP} - 剩余尝试次数: ${remainingAttempts}`);
            
            // 登录失败
            res.status(401).json({ 
                success: false, 
                message: `用户名或密码错误，剩余${remainingAttempts}次尝试机会` 
            });
        }
    } catch (error) {
        console.error('登录处理失败:', error);
        res.status(500).json({ success: false, message: '服务器错误' });
    }
});

// 登出API - 增强安全性
app.get('/api/logout', (req, res) => {
    try {
        // 获取用户信息用于日志
        const username = req.session?.user?.username || '未知用户';
        const clientIP = req.ip || req.connection.remoteAddress;
        
        // 销毁会话
        req.session.destroy((err) => {
            if (err) {
                console.error('会话销毁失败:', err);
                return res.status(500).json({ success: false, message: '登出失败' });
            }
            
            // 清除Cookie
            res.clearCookie('connect.sid');
            
            // 记录登出
            console.log(`用户登出成功: ${username} - IP: ${clientIP}`);
            
            // 返回成功响应
            res.json({ success: true, message: '登出成功' });
        });
    } catch (error) {
        console.error('登出处理失败:', error);
        res.status(500).json({ success: false, message: '服务器错误' });
    }
});

// 登录页面
app.get('/login', (req, res) => {
    try {
        const loginHtmlPath = path.join(__dirname, 'login.html');
        res.sendFile(loginHtmlPath);
    } catch (error) {
        console.error('访问登录页面失败:', error);
        res.status(500).json({ error: '访问登录页面失败' });
    }
});

// 重定向 /admin.html 到 /admin
app.get('/admin.html', (req, res) => {
    res.redirect(301, '/admin');
});

// 管理界面 - 添加会话验证保护
app.get('/admin', ensureAuthenticated, (req, res) => {
    try {
        const adminHtmlPath = path.join(__dirname, 'admin.html');
        res.sendFile(adminHtmlPath);
    } catch (error) {
        console.error('访问管理界面失败:', error);
        res.status(500).json({ error: '访问管理界面失败' });
    }
});

// 获取所有业务服务（前端展示用）
app.get('/api/services', async (req, res) => {
    try {
        if (useDatabase) {
            // 使用数据库模式
            const connection = await pool.getConnection();
            try {
                const [results] = await connection.execute(
                    'SELECT * FROM services WHERE is_active = 1 ORDER BY id ASC'
                );
                res.json(results);
            } finally {
                connection.release();
            }
        } else {
            // 使用文件存储模式
            const services = JSON.parse(fs.readFileSync(SERVICES_FILE, 'utf8'));
            const activeServices = services.filter(service => service.is_active).sort((a, b) => (parseInt(a.id) || 0) - (parseInt(b.id) || 0));
            res.json(activeServices);
        }
    } catch (error) {
        console.error('获取业务服务数据失败:', error);
        res.status(500).json({ error: '获取业务服务数据失败' });
    }
});

// 生成随机颜色主题的函数
function generateRandomColorTheme() {
    // 预定义的颜色主题，每个主题包含文本颜色和背景渐变颜色
    const colorThemes = [
        { textColor: 'text-blue-700', bgGradient: 'bg-gradient-to-br from-blue-50 to-blue-100' },
        { textColor: 'text-green-700', bgGradient: 'bg-gradient-to-br from-green-50 to-green-100' },
        { textColor: 'text-yellow-600', bgGradient: 'bg-gradient-to-br from-yellow-50 to-yellow-100' },
        { textColor: 'text-purple-700', bgGradient: 'bg-gradient-to-br from-purple-50 to-purple-100' },
        { textColor: 'text-indigo-700', bgGradient: 'bg-gradient-to-br from-indigo-50 to-indigo-100' },
        { textColor: 'text-pink-700', bgGradient: 'bg-gradient-to-br from-pink-50 to-pink-100' },
        { textColor: 'text-red-700', bgGradient: 'bg-gradient-to-br from-red-50 to-red-100' },
        { textColor: 'text-orange-700', bgGradient: 'bg-gradient-to-br from-orange-50 to-orange-100' },
        { textColor: 'text-teal-700', bgGradient: 'bg-gradient-to-br from-teal-50 to-teal-100' },
        { textColor: 'text-cyan-700', bgGradient: 'bg-gradient-to-br from-cyan-50 to-cyan-100' }
    ];
    
    // 随机选择一个主题
    const randomIndex = Math.floor(Math.random() * colorThemes.length);
    return colorThemes[randomIndex];
}

// 获取所有业务服务（管理后台用，包括非激活状态）
app.get('/api/admin/services', ensureAuthenticated, async (req, res) => {
    try {
        // 获取分页和搜索参数
        const page = parseInt(req.query.page) || 1;
        const pageSize = parseInt(req.query.pageSize) || 10;
        const search = req.query.search || '';
        const offset = (page - 1) * pageSize;
        
        console.log('API请求参数:', { page, pageSize, search, offset });
        console.log('数据库模式状态:', useDatabase ? '使用数据库' : '使用文件存储');
        
        let services = [];
        let total = 0;
        
        if (useDatabase) {
            // 使用数据库模式
            const connection = await pool.getConnection();
            try {
                // 构建查询（直接在SQL中使用数值，避免参数绑定问题）
                const limit = pageSize;
                const skip = offset;
                
                if (search) {
                    // 有搜索条件的情况 - 使用参数绑定仅用于字符串搜索条件
                    const searchParam = `%${search}%`;
                    query = `SELECT * FROM services WHERE title LIKE ? OR description LIKE ? ORDER BY id ASC LIMIT ${limit} OFFSET ${skip}`;
                    countQuery = 'SELECT COUNT(*) as count FROM services WHERE title LIKE ? OR description LIKE ?';
                    queryParams = [searchParam, searchParam];
                    countParams = [searchParam, searchParam];
                } else {
                    // 没有搜索条件的情况 - 直接在SQL中使用数值
                    query = `SELECT * FROM services ORDER BY id ASC LIMIT ${limit} OFFSET ${skip}`;
                    countQuery = 'SELECT COUNT(*) as count FROM services';
                    queryParams = [];
                    countParams = [];
                }
                
                console.log('执行查询:', query, '参数:', queryParams);
                console.log('执行计数查询:', countQuery, '参数:', countParams);
                
                // 执行查询
                console.log('准备执行查询，参数类型检查:', { limit: typeof limit, skip: typeof skip });
                // 确保参数类型正确
                const safeQueryParams = queryParams.map(param => param === undefined ? null : param);
                const safeCountParams = countParams.map(param => param === undefined ? null : param);
                
                console.log('修正后的查询参数:', safeQueryParams);
                console.log('修正后的计数查询参数:', safeCountParams);
                
                const [results] = await connection.execute(query, safeQueryParams);
                const [countResult] = await connection.execute(countQuery, safeCountParams);
                
                services = results;
                total = countResult[0].count;
                console.log('数据库查询结果:', JSON.stringify(results, null, 2));
                console.log('数据库查询成功，返回', results.length, '条记录，总数:', total);
            } finally {
                connection.release();
            }
        } else {
            // 使用文件存储模式
            const allServices = JSON.parse(fs.readFileSync(SERVICES_FILE, 'utf8'));
            
            // 搜索过滤
            let filteredServices = allServices;
            if (search) {
                filteredServices = allServices.filter(service => 
                    service.title.toLowerCase().includes(search.toLowerCase()) ||
                    service.description.toLowerCase().includes(search.toLowerCase())
                );
            }
            
            // 排序 - 按照id字段升序排序
            filteredServices.sort((a, b) => (parseInt(a.id) || 0) - (parseInt(b.id) || 0));
            
            // 分页
            total = filteredServices.length;
            services = filteredServices.slice(offset, offset + pageSize);
        }
        
        // 返回前端期望的格式
            console.log('最终返回给前端的数据:', { services: services.length, total });
            res.json({
                services: services,
                total: total
            });
    } catch (error) {
        console.error('获取业务服务管理数据失败:', error);
        res.status(500).json({ error: '获取业务服务管理数据失败' });
    }
});

// 创建新的业务服务
app.post('/api/services', ensureAuthenticated, async (req, res) => {
    try {
        const { title, icon, iconColor, iconBg, description, features, result, order } = req.body;
        
        // 验证必要字段
        if (!title || !description || !features || !Array.isArray(features)) {
            return res.status(400).json({ error: '缺少必要字段' });
        }
        
        // 生成随机颜色主题
        const colorTheme = generateRandomColorTheme();
        
        const newService = {
            title,
            icon: icon || 'fa-cogs',
            iconColor: iconColor || colorTheme.textColor, // 使用随机主题的文本颜色
            iconBg: iconBg || colorTheme.bgGradient, // 使用随机主题的背景渐变
            description,
            features,
            result: result || '',
            order: order || 0,
            is_active: true,
            created_at: new Date().toISOString(),
            updated_at: new Date().toISOString()
        };
        
        if (useDatabase) {
            // 使用数据库模式
            const connection = await pool.getConnection();
            try {
                // 先查询services表中的最大ID
                const [maxIdResult] = await connection.execute('SELECT MAX(id) as max_id FROM services');
                const maxId = maxIdResult[0].max_id || 0;
                
                // 使用显式的字段和值插入，并设置ID为maxId + 1
                // 需要将features数组转换为JSON字符串
                const featuresJson = JSON.stringify(newService.features);
                
                const [result] = await connection.execute(
                    `INSERT INTO services (id, title, icon, iconColor, iconBg, description, features, result, 
                    \`order\`, is_active) 
                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
                    [
                        maxId + 1,
                        newService.title,
                        newService.icon,
                        newService.iconColor,
                        newService.iconBg,
                        newService.description,
                        featuresJson,
                        newService.result,
                        newService.order,
                        newService.is_active
                    ]
                );
                newService.id = maxId + 1; // 使用我们计算的ID而不是数据库返回的
                res.json(newService);
            } finally {
                connection.release();
            }
        } else {
            // 使用文件存储模式
            const services = JSON.parse(fs.readFileSync(SERVICES_FILE, 'utf8'));
            newService.id = Math.max(0, ...services.map(s => s.id)) + 1;
            services.push(newService);
            fs.writeFileSync(SERVICES_FILE, JSON.stringify(services, null, 2));
            res.json(newService);
        }
    } catch (error) {
        console.error('创建业务服务失败:', error);
        res.status(500).json({ error: '创建业务服务失败' });
    }
});

// 更新业务服务 - 支持前端调用的路径
app.put('/api/admin/services/:id', ensureAuthenticated, async (req, res) => {
    try {
        // 添加详细日志记录
        const serviceId = parseInt(req.params.id);
        console.log(`开始更新服务，ID: ${serviceId}`);
        console.log('请求体数据:', JSON.stringify(req.body));
        
        const { title, icon, iconColor, iconBg, description, features, result, order, is_active } = req.body;
        
        // 验证必填字段
        if (!title || !description) {
            console.log('更新失败：缺少必填字段');
            return res.status(400).json({ error: '缺少必填字段：标题和描述' });
        }
        
        // 创建更新对象
        const updatedService = {};
        
        // 基本字段
        updatedService.title = title;
        updatedService.icon = icon || 'fa-cogs';
        updatedService.description = description;
        updatedService.features = features || [];
        updatedService.result = result || '';
        updatedService.order = order ?? 0;
        updatedService.is_active = typeof is_active === 'boolean' ? is_active : true;
        updatedService.updated_at = new Date().toISOString();
        
        // 颜色处理逻辑
        if (!iconColor && !iconBg) {
            const colorTheme = generateRandomColorTheme();
            updatedService.iconColor = colorTheme.textColor;
            updatedService.iconBg = colorTheme.bgGradient;
            console.log('生成随机颜色主题:', updatedService.iconColor, updatedService.iconBg);
        } else {
            updatedService.iconColor = iconColor || 'text-blue-700';
            updatedService.iconBg = iconBg || 'bg-gradient-to-br from-blue-50 to-blue-100';
        }
        
        if (useDatabase) {
            // 数据库模式
            console.log('使用数据库模式更新服务');
            const connection = await pool.getConnection();
            try {
                // 先检查服务是否存在
                const [checkResult] = await connection.execute(
                    'SELECT * FROM services WHERE id = ?',
                    [serviceId]
                );
                
                if (checkResult.length === 0) {
                    console.log(`更新失败：ID为${serviceId}的服务不存在`);
                    return res.status(404).json({ error: '业务服务不存在' });
                }
                
                const serviceData = {
                    ...updatedService,
                    features: Array.isArray(updatedService.features) ? JSON.stringify(updatedService.features) : updatedService.features
                };
                
                const params = [
                    serviceData.title ?? null,
                    serviceData.icon ?? null,
                    serviceData.iconColor ?? null,
                    serviceData.iconBg ?? null,
                    serviceData.description ?? null,
                    serviceData.features ?? null,
                    serviceData.result ?? null,
                    serviceData.order ?? 0,
                    serviceData.is_active ? 1 : 0,
                    serviceId
                ];
                
                console.log('执行更新SQL，参数:', params);
                const [result] = await connection.execute(
                    `UPDATE services SET 
                    title = ?, 
                    icon = ?, 
                    iconColor = ?, 
                    iconBg = ?, 
                    description = ?, 
                    features = ?, 
                    result = ?, 
                    \`order\` = ?, 
                    is_active = ?, 
                    updated_at = CURRENT_TIMESTAMP 
                    WHERE id = ?`,
                    params
                );
                
                console.log('更新结果:', result);
                if (result.affectedRows === 0) {
                    console.log(`更新失败：ID为${serviceId}的服务不存在或更新未生效`);
                    return res.status(404).json({ error: '业务服务不存在或更新未生效' });
                }
                
                updatedService.id = serviceId;
                console.log(`服务更新成功，ID: ${serviceId}`);
                res.json(updatedService);
            } finally {
                connection.release();
            }
        } else {
            // 文件存储模式
            console.log('使用文件存储模式更新服务');
            const services = JSON.parse(fs.readFileSync(SERVICES_FILE, 'utf8'));
            const index = services.findIndex(s => s.id === serviceId);
            if (index === -1) {
                console.log(`更新失败：ID为${serviceId}的服务不存在`);
                return res.status(404).json({ error: '业务服务不存在' });
            }
            services[index] = { ...services[index], ...updatedService, id: serviceId };
            fs.writeFileSync(SERVICES_FILE, JSON.stringify(services, null, 2));
            console.log(`服务更新成功，ID: ${serviceId}`);
            res.json(services[index]);
        }
    } catch (error) {
        console.error('更新业务服务失败:', error.message, error.stack);
        res.status(500).json({ error: '更新业务服务失败', details: error.message });
    }
});

// 切换服务状态
app.put('/api/admin/services/:id/toggle-status', ensureAuthenticated, async (req, res) => {
    try {
        const serviceId = parseInt(req.params.id);
        const targetStatus = req.body.is_active; // 这是前端期望的目标状态
        
        console.log('[状态切换] 开始切换服务状态，ID:', serviceId);
        console.log('[状态切换] 请求目标状态:', targetStatus, '类型:', typeof targetStatus);
        
        if (useDatabase) {
            // 数据库模式
            console.log('[状态切换] 使用数据库模式');
            const connection = await pool.getConnection();
            try {
                // 首先查询当前状态，确保正确切换
                console.log('[状态切换] 查询服务当前状态');
                const [currentData] = await connection.execute(
                    'SELECT is_active FROM services WHERE id = ?',
                    [serviceId]
                );
                
                if (currentData.length === 0) {
                    console.log(`[状态切换] 服务不存在，ID: ${serviceId}`);
                    return res.status(404).json({ error: '业务服务不存在', details: `ID为${serviceId}的服务不存在` });
                }
                
                const currentStatus = currentData[0].is_active === 1;
                const finalStatus = typeof targetStatus === 'boolean' ? targetStatus : !currentStatus;
                
                console.log('[状态切换] 状态详情:', { currentStatus, targetStatus, finalStatus });
                
                console.log('[状态切换] 执行更新SQL');
                const [result] = await connection.execute(
                    'UPDATE services SET is_active = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?',
                    [finalStatus ? 1 : 0, serviceId]
                );
                
                console.log('[状态切换] 更新结果:', result);
                if (result.affectedRows === 0) {
                    console.log(`[状态切换] 更新未生效，服务ID: ${serviceId}`);
                    return res.status(404).json({ error: '业务服务不存在或更新未生效' });
                }
                
                console.log(`[状态切换] 服务状态切换成功，ID: ${serviceId}，新状态: ${finalStatus}`);
                res.json({ success: true, id: serviceId, is_active: finalStatus });
            } finally {
                connection.release();
            }
        } else {
            // 文件存储模式
            console.log('[状态切换] 使用文件存储模式');
            const services = JSON.parse(fs.readFileSync(SERVICES_FILE, 'utf8'));
            const index = services.findIndex(s => s.id === serviceId);
            if (index === -1) {
                console.log(`[状态切换] 服务不存在，ID: ${serviceId}`);
                return res.status(404).json({ error: '业务服务不存在', details: `ID为${serviceId}的服务不存在` });
            }
            
            const currentStatus = services[index].is_active;
            const finalStatus = typeof targetStatus === 'boolean' ? targetStatus : !currentStatus;
            
            console.log('[状态切换] 状态详情:', { currentStatus, targetStatus, finalStatus });
            
            services[index].is_active = finalStatus;
            services[index].updated_at = new Date().toISOString();
            fs.writeFileSync(SERVICES_FILE, JSON.stringify(services, null, 2));
            console.log(`[状态切换] 服务状态切换成功，ID: ${serviceId}，新状态: ${finalStatus}`);
            res.json({ success: true, id: serviceId, is_active: finalStatus });
        }
    } catch (error) {
        console.error('[状态切换] 切换服务状态失败:', error.message, error.stack);
        res.status(500).json({ error: '切换服务状态失败', details: error.message });
    }
});

// 更新业务服务 - 原始路径保持向后兼容
app.put('/api/services/:id', ensureAuthenticated, async (req, res) => {
    try {
        // 添加详细日志记录
        const serviceId = parseInt(req.params.id);
        console.log(`[原始路径] 开始更新服务，ID: ${serviceId}`);
        console.log('[原始路径] 请求体数据:', JSON.stringify(req.body));
        
        const { title, icon, iconColor, iconBg, description, features, result, order, is_active } = req.body;
        
        // 验证必填字段
        if (!title || !description) {
            console.log('[原始路径] 更新失败：缺少必填字段');
            return res.status(400).json({ error: '缺少必填字段：标题和描述' });
        }
        
        // 创建更新对象
        const updatedService = {};
        
        // 基本字段
        updatedService.title = title;
        updatedService.icon = icon || 'fa-cogs';
        updatedService.description = description;
        updatedService.features = features || [];
        updatedService.result = result || '';
        updatedService.order = order ?? 0;
        updatedService.is_active = typeof is_active === 'boolean' ? is_active : true;
        updatedService.updated_at = new Date().toISOString();
        
        // 颜色处理逻辑
        if (!iconColor && !iconBg) {
            const colorTheme = generateRandomColorTheme();
            updatedService.iconColor = colorTheme.textColor;
            updatedService.iconBg = colorTheme.bgGradient;
            console.log('[原始路径] 生成随机颜色主题:', updatedService.iconColor, updatedService.iconBg);
        } else {
            updatedService.iconColor = iconColor || 'text-blue-700';
            updatedService.iconBg = iconBg || 'bg-gradient-to-br from-blue-50 to-blue-100';
        }
        
        if (useDatabase) {
            // 使用数据库模式
            console.log('[原始路径] 使用数据库模式更新服务');
            const connection = await pool.getConnection();
            try {
                // 开启事务
                await connection.beginTransaction();
                
                // 先检查服务是否存在
                const [checkResult] = await connection.execute(
                    'SELECT * FROM services WHERE id = ?',
                    [serviceId]
                );
                
                if (checkResult.length === 0) {
                    console.log(`[原始路径] 更新失败：ID为${serviceId}的服务不存在`);
                    await connection.rollback();
                    return res.status(404).json({ error: '业务服务不存在' });
                }
                
                // 需要将features数组转换为JSON字符串
                const serviceData = {
                    ...updatedService,
                    features: Array.isArray(updatedService.features) ? JSON.stringify(updatedService.features) : updatedService.features
                };
                
                // 确保所有参数都有值，将undefined转换为null
                const params = [
                    serviceData.title ?? null,
                    serviceData.icon ?? null,
                    serviceData.iconColor ?? null,
                    serviceData.iconBg ?? null,
                    serviceData.description ?? null,
                    serviceData.features ?? null,
                    serviceData.result ?? null,
                    serviceData.order ?? 0, // 默认顺序为0
                    serviceData.is_active ? 1 : 0, // 确保布尔值正确转换为数据库值
                    serviceId
                ];
                
                console.log('[原始路径] 执行更新SQL，参数:', params);
                // 使用显式字段更新，避免SET ?语法问题
                // 使用CURRENT_TIMESTAMP更新updated_at
                const [result] = await connection.execute(
                    `UPDATE services SET 
                    title = ?, 
                    icon = ?, 
                    iconColor = ?, 
                    iconBg = ?, 
                    description = ?, 
                    features = ?, 
                    result = ?, 
                    \`order\` = ?, 
                    is_active = ?, 
                    updated_at = CURRENT_TIMESTAMP 
                    WHERE id = ?`,
                    params
                );
                
                console.log('[原始路径] 更新结果:', result);
                if (result.affectedRows === 0) {
                    console.log(`[原始路径] 更新失败：ID为${serviceId}的服务不存在或更新未生效`);
                    await connection.rollback();
                    return res.status(404).json({ error: '业务服务不存在或更新未生效' });
                }
                
                // 提交事务
                await connection.commit();
                
                updatedService.id = serviceId;
                console.log(`[原始路径] 服务更新成功，ID: ${serviceId}`);
                res.json(updatedService);
            } catch (error) {
                // 发生错误时回滚事务
                await connection.rollback();
                console.error('创建岗位时数据库错误:', error);
                res.status(500).json({ error: '创建岗位失败', details: error.message });
                return; // 确保不继续执行
            } finally {
                connection.release();
            }
        } else {
            // 使用文件存储模式
            console.log('[原始路径] 使用文件存储模式更新服务');
            const services = JSON.parse(fs.readFileSync(SERVICES_FILE, 'utf8'));
            const index = services.findIndex(s => s.id === serviceId);
            if (index === -1) {
                console.log(`[原始路径] 更新失败：ID为${serviceId}的服务不存在`);
                return res.status(404).json({ error: '业务服务不存在' });
            }
            services[index] = { ...services[index], ...updatedService, id: serviceId };
            fs.writeFileSync(SERVICES_FILE, JSON.stringify(services, null, 2));
            console.log(`[原始路径] 服务更新成功，ID: ${serviceId}`);
            res.json(services[index]);
        }
    } catch (error) {
        console.error('[原始路径] 更新业务服务失败:', error.message, error.stack);
        res.status(500).json({ error: '更新业务服务失败', details: error.message });
    }
});

// 删除业务服务
app.delete('/api/services/:id', ensureAuthenticated, async (req, res) => {
    try {
        const serviceId = parseInt(req.params.id);
        
        if (useDatabase) {
            // 使用数据库模式
            const connection = await pool.getConnection();
            try {
                // 开启事务
                await connection.beginTransaction();
                
                // 1. 执行删除操作
                const [result] = await connection.execute(
                    'DELETE FROM services WHERE id = ?',
                    [serviceId]
                );
                if (result.affectedRows === 0) {
                    await connection.rollback();
                    return res.status(404).json({ error: '业务服务不存在' });
                }
                
                // 2. 重新编号所有大于删除ID的记录
                await connection.execute(
                    'UPDATE services SET id = id - 1 WHERE id > ? ORDER BY id',
                    [serviceId]
                );
                
                // 提交事务
                await connection.commit();
                
                console.log(`成功删除业务服务ID: ${serviceId}，并重新编号`);
                res.json({ message: '业务服务删除成功，ID已自动重新编号' });
            } catch (error) {
                // 发生错误时回滚事务
                await connection.rollback();
                console.error('更新岗位时数据库错误:', error);
                res.status(500).json({ error: '更新岗位失败', details: error.message });
                return; // 确保不继续执行
            } finally {
                connection.release();
            }
        } else {
            // 使用文件存储模式
            const services = JSON.parse(fs.readFileSync(SERVICES_FILE, 'utf8'));
            const newServices = services.filter(s => s.id !== serviceId);
            if (newServices.length === services.length) {
                return res.status(404).json({ error: '业务服务不存在' });
            }
            
            // 重新编号所有记录
            for (let i = 0; i < newServices.length; i++) {
                newServices[i].id = i + 1;
            }
            
            fs.writeFileSync(SERVICES_FILE, JSON.stringify(newServices, null, 2));
            console.log(`成功删除业务服务ID: ${serviceId}，并重新编号`);
            res.json({ message: '业务服务删除成功，ID已自动重新编号' });
        }
    } catch (error) {
        console.error('删除业务服务失败:', error);
        res.status(500).json({ error: '删除业务服务失败' });
    }
});

// 获取所有岗位信息
app.get('/api/job-postings', async (req, res) => {
    try {
        if (useDatabase) {
            // 使用数据库模式
            const connection = await pool.getConnection();
            try {
                const [results] = await connection.execute(
                    'SELECT * FROM job_postings WHERE is_active = 1 ORDER BY created_at DESC'
                );
                res.json(results);
            } finally {
                connection.release();
            }
        } else {
            // 使用文件存储模式
            const jobPostings = JSON.parse(fs.readFileSync(JOB_POSTINGS_FILE, 'utf8'));
            const activeJobs = jobPostings.filter(job => job.is_active).sort((a, b) => 
                new Date(b.created_at) - new Date(a.created_at)
            );
            res.json(activeJobs);
        }
    } catch (error) {
        console.error('获取岗位信息失败:', error);
        res.status(500).json({ error: '获取岗位信息失败' });
    }
});

// 管理系统获取所有岗位（包括非激活的）- 支持分页
app.get('/api/admin/job-postings', ensureAuthenticated, async (req, res) => {
    try {
        // 获取分页参数，设置默认值并确保是数字类型，最多每页10条数据
        const page = Number(req.query.page) || 1;
        const limit = Math.min(Number(req.query.limit) || 10, 10); // 默认每页10条，最多10条数据
        const offset = (page - 1) * limit;
        
        if (useDatabase) {
            // 使用数据库模式
            const connection = await pool.getConnection();
            try {
                // 执行计数查询
                const [countResult] = await connection.execute('SELECT COUNT(*) as total FROM job_postings');
                // 使用参数化查询避免SQL注入风险
                const [rows] = await connection.execute(
                    'SELECT * FROM job_postings ORDER BY id DESC LIMIT ? OFFSET ?',
                    [limit, offset]
                );
                
                const total = countResult[0].total;
                const totalPages = Math.ceil(total / limit);
                
                // 返回分页数据和元信息
                res.json({
                    data: rows,
                    pagination: {
                        total,
                        page,
                        limit,
                        totalPages
                    }
                });
            } finally {
                connection.release();
            }
        } else {
            // 使用文件存储模式
            const jobPostings = JSON.parse(fs.readFileSync(JOB_POSTINGS_FILE, 'utf8'));
            // 按ID降序排序，显示最新的岗位在前面
            const sortedJobs = jobPostings.sort((a, b) => b.id - a.id);
            
            // 计算分页数据
            const total = sortedJobs.length;
            const paginatedData = sortedJobs.slice(offset, offset + limit);
            const totalPages = Math.ceil(total / limit);
            
            // 返回分页数据和元信息
            res.json({
                data: paginatedData,
                pagination: {
                    total,
                    page,
                    limit,
                    totalPages
                }
            });
        }
    } catch (error) {
        console.error('获取岗位信息失败:', error);
        res.status(500).json({ error: '获取岗位信息失败' });
    }
});

// 创建新岗位
app.post('/api/job-postings', ensureAuthenticated, async (req, res) => {
    try {
        console.log('[DEBUG] 收到新增岗位请求，用户会话ID:', req.sessionID);
        console.log('[DEBUG] 请求体内容:', req.body);
        
        // 直接使用req.body而不是解构，确保所有字段都能正确获取
        const title = req.body.title;
        const category = req.body.category || '';
        const location = req.body.location || '';
        const salary = req.body.salary || '';
        const responsibilities = req.body.responsibilities;
        const requirements = req.body.requirements;
        const highlights = req.body.highlights || '';
        const tech_stack = req.body.tech_stack || '';
        const is_active = req.body.is_active !== undefined ? req.body.is_active : true;
        
        console.log('[DEBUG] 处理后的字段值:');
        console.log('[DEBUG] - title:', title);
        console.log('[DEBUG] - category:', category);
        console.log('[DEBUG] - location:', location);
        console.log('[DEBUG] - salary:', salary);
        console.log('[DEBUG] - responsibilities:', !!responsibilities ? '有值' : '无值');
        console.log('[DEBUG] - requirements:', !!requirements ? '有值' : '无值');
        console.log('[DEBUG] - highlights:', highlights);
        console.log('[DEBUG] - tech_stack:', tech_stack);
        console.log('[DEBUG] - is_active:', is_active);
        
        // 验证必填字段
        if (!title || !responsibilities || !requirements) {
            console.log('[ERROR] 必填字段验证失败:', { title: !!title, hasResponsibilities: !!responsibilities, hasRequirements: !!requirements });
            return res.status(400).json({ error: '岗位名称、职责和要求为必填项', details: { title: !!title, hasResponsibilities: !!responsibilities, hasRequirements: !!requirements } });
        }
        
        if (useDatabase) {
            // 使用数据库模式
            const connection = await pool.getConnection();
            try {
                // 开启事务
                await connection.beginTransaction();
                
                const [result] = await connection.execute(
                    'INSERT INTO job_postings (title, category, location, salary, responsibilities, requirements, highlights, tech_stack, is_active) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
                    [title, category || '', location || '', salary || '', responsibilities, requirements, highlights || '', tech_stack || '', req.body.is_active !== undefined ? req.body.is_active : true]
                );
                
                // 插入后立即重新编排所有记录的ID - 使用更可靠的方式
                await connection.query('SET @rank = 0');
                await connection.query('UPDATE job_postings SET id = (@rank := @rank + 1) ORDER BY created_at ASC');
                
                // 重置表的自增计数器，确保下次插入从正确的ID开始
                // 先查询最大ID值，然后设置AUTO_INCREMENT（MySQL不支持ALTER中直接使用参数化查询）
                const [maxIdResult] = await connection.execute('SELECT COALESCE(MAX(id), 0) + 1 as nextId FROM job_postings');
                const nextId = maxIdResult[0].nextId;
                // 使用字符串拼接而非参数化查询，因为ALTER TABLE不支持参数占位符
                await connection.query(`ALTER TABLE job_postings AUTO_INCREMENT = ${nextId}`);
                
                // 提交事务
                await connection.commit();
                
                // 获取插入的记录，使用ID重新编排后的查询方式
                const [results] = await connection.execute('SELECT * FROM job_postings ORDER BY created_at DESC LIMIT 1');
                
                res.status(201).json(results[0]);
            } catch (error) {
                // 发生错误时回滚事务
                await connection.rollback();
                console.error('创建岗位时数据库错误:', error);
                res.status(500).json({ error: '创建岗位失败', details: error.message });
                return; // 确保不继续执行
            } finally {
                connection.release();
            }
        } else {
            // 使用文件存储模式
            let jobPostings = JSON.parse(fs.readFileSync(JOB_POSTINGS_FILE, 'utf8'));
            
            const newJob = {
                id: jobPostings.length + 1, // 临时ID，稍后会重新编排
                title,
                category: category || '',
                location: location || '',
                salary: salary || '',
                responsibilities,
                requirements,
                highlights: highlights || '',
                tech_stack: tech_stack || '',
                is_active: req.body.is_active !== undefined ? req.body.is_active : true,
                created_at: new Date().toISOString(),
                updated_at: new Date().toISOString()
            };
            
            jobPostings.push(newJob);
            
            // 重新编排ID，确保连续 - 按创建时间升序排序
            jobPostings = jobPostings.sort((a, b) => new Date(a.created_at) - new Date(b.created_at))
                .map((job, index) => ({ ...job, id: index + 1 }));
            
            fs.writeFileSync(JOB_POSTINGS_FILE, JSON.stringify(jobPostings));
            // 找到新创建的岗位，使用更可靠的方式：按创建时间排序后取最后一个
            // 因为我们刚刚push了newJob，然后重新排序并重编了ID，所以最后一个就是最新的
            const createdJob = jobPostings[jobPostings.length - 1];
            console.log('成功创建新岗位:', createdJob);
            res.status(201).json(createdJob);
        }
    } catch (error) {
        console.error('创建岗位失败详情:', error);
        res.status(500).json({ error: '创建岗位失败', details: error.message });
    }
});

// 更新岗位信息
app.put('/api/job-postings/:id', ensureAuthenticated, async (req, res) => {
    try {
        const { id } = req.params;
        const updateData = req.body;
        
        if (useDatabase) {
            // 使用数据库模式
            const connection = await pool.getConnection();
            try {
                // 开启事务
                await connection.beginTransaction();
                
                // 动态构建更新语句
                const setClauses = [];
                const params = [];
                
                if (updateData.title !== undefined) { setClauses.push('title = ?'); params.push(updateData.title || ''); }
                if (updateData.category !== undefined) { setClauses.push('category = ?'); params.push(updateData.category || ''); }
                if (updateData.location !== undefined) { setClauses.push('location = ?'); params.push(updateData.location || ''); }
                if (updateData.salary !== undefined) { setClauses.push('salary = ?'); params.push(updateData.salary || ''); }
                if (updateData.responsibilities !== undefined) { setClauses.push('responsibilities = ?'); params.push(updateData.responsibilities || ''); }
                if (updateData.requirements !== undefined) { setClauses.push('requirements = ?'); params.push(updateData.requirements || ''); }
                if (updateData.highlights !== undefined) { setClauses.push('highlights = ?'); params.push(updateData.highlights || ''); }
                if (updateData.tech_stack !== undefined) { setClauses.push('tech_stack = ?'); params.push(updateData.tech_stack || ''); }
                if (updateData.is_active !== undefined) { setClauses.push('is_active = ?'); params.push(updateData.is_active ? 1 : 0); }
                
                // 总是更新updated_at时间戳
                setClauses.push('updated_at = CURRENT_TIMESTAMP');
                
                params.push(id);
                
                const [result] = await connection.execute(
                    `UPDATE job_postings SET ${setClauses.join(', ')} WHERE id = ?`,
                    params
                );
                
                // 检查是否有记录被更新
                if (result.affectedRows === 0) {
                    await connection.rollback();
                    return res.status(404).json({ error: '岗位不存在' });
                }
                
                // 提交事务
                await connection.commit();
                
                // 获取更新后的记录
                const [results] = await connection.execute('SELECT * FROM job_postings WHERE id = ?', [id]);
                if (results.length === 0) {
                    return res.status(404).json({ error: '岗位不存在' });
                }
                
                res.json(results[0]);
            } catch (error) {
                // 发生错误时回滚事务
                await connection.rollback();
                console.error('更新岗位时数据库错误:', error);
                res.status(500).json({ error: '更新岗位失败', details: error.message });
                return; // 确保不继续执行
            } finally {
                connection.release();
            }
        } else {
            // 使用文件存储模式
            let jobPostings = JSON.parse(fs.readFileSync(JOB_POSTINGS_FILE, 'utf8'));
            const jobIndex = jobPostings.findIndex(job => job.id === parseInt(id));
            
            if (jobIndex === -1) {
                return res.status(404).json({ error: '岗位不存在' });
            }
            
            // 更新岗位信息，仅更新提供的字段，保留原有ID
            const originalJob = jobPostings[jobIndex];
            const updatedJob = { ...originalJob, ...updateData, updated_at: new Date().toISOString() };
            
            // 确保所有字段都被正确处理
            jobPostings[jobIndex] = updatedJob;
            
            fs.writeFileSync(JOB_POSTINGS_FILE, JSON.stringify(jobPostings));
            
            // 返回更新后的岗位
            res.json(updatedJob);
        }
    } catch (error) {
        console.error('更新岗位失败:', error);
        res.status(500).json({ error: '更新岗位失败' });
    }
});

// 删除岗位
app.delete('/api/job-postings/:id', ensureAuthenticated, async (req, res) => {
    try {
        const { id } = req.params;
        
        if (useDatabase) {
            // 使用数据库模式
            const connection = await pool.getConnection();
            try {
                // 开启事务
                await connection.beginTransaction();
                
                const [result] = await connection.execute('DELETE FROM job_postings WHERE id = ?', [id]);
                
                if (result.affectedRows === 0) {
                    await connection.rollback();
                    return res.status(404).json({ error: '岗位不存在' });
                }
                
                // 删除后重新编排所有记录的ID - 使用更可靠的方式
                await connection.query('SET @rank = 0');
                await connection.query('UPDATE job_postings SET id = (@rank := @rank + 1) ORDER BY created_at ASC');
                
                // 重置表的自增计数器，确保下次插入从正确的ID开始
                // 先查询最大ID值，然后设置AUTO_INCREMENT（MySQL不支持ALTER中直接使用子查询或参数化查询）
                const [maxIdResult] = await connection.execute('SELECT COALESCE(MAX(id), 0) + 1 as nextId FROM job_postings');
                const nextId = maxIdResult[0].nextId;
                // 使用字符串拼接而非参数化查询，因为ALTER TABLE不支持参数占位符
                await connection.query(`ALTER TABLE job_postings AUTO_INCREMENT = ${nextId}`);
                
                // 提交事务
                await connection.commit();
                
                res.json({ message: '岗位删除成功', reindexed: true });
            } catch (error) {
                // 发生错误时回滚事务
                await connection.rollback();
                console.error('删除岗位时数据库错误:', error);
                res.status(500).json({ error: '删除岗位失败', details: error.message });
                return; // 确保不继续执行
            } finally {
                connection.release();
            }
        } else {
            // 使用文件存储模式
            let jobPostings = JSON.parse(fs.readFileSync(JOB_POSTINGS_FILE, 'utf8'));
            const filteredJobs = jobPostings.filter(job => job.id !== parseInt(id));
            
            if (filteredJobs.length === jobPostings.length) {
                return res.status(404).json({ error: '岗位不存在' });
            }
            
            // 重新编排ID，确保连续 - 按创建时间升序排序
            const reindexedJobs = filteredJobs.sort((a, b) => new Date(a.created_at) - new Date(b.created_at))
                .map((job, index) => ({ ...job, id: index + 1 }));
            
            fs.writeFileSync(JOB_POSTINGS_FILE, JSON.stringify(reindexedJobs));
            res.json({ message: '岗位删除成功', reindexed: true });
        }
    } catch (error) {
        console.error('删除岗位失败:', error);
        res.status(500).json({ error: '删除岗位失败' });
    }
});

// 测试下载接口 - 用于诊断下载功能
app.get('/api/test-download', (req, res) => {
    try {
        console.log(`[${new Date().toISOString()}] 测试下载接口被调用`);
        
        // 创建一个简单的测试文件内容
        const testContent = Buffer.from('这是一个测试文件内容，用于验证下载功能是否正常工作。\nTimestamp: ' + new Date().toISOString());
        
        // 设置响应头
        res.setHeader('Content-Type', 'text/plain');
        res.setHeader('Content-Disposition', 'attachment; filename="test_file.txt"');
        res.setHeader('Content-Length', testContent.length);
        res.setHeader('Connection', 'keep-alive');
        
        // 发送文件内容
        res.end(testContent);
        
        console.log(`[${new Date().toISOString()}] 测试下载接口响应成功`);
    } catch (error) {
        console.error(`[${new Date().toISOString()}] 测试下载接口错误:`, error);
        res.status(500).json({ error: '测试下载失败', details: error.message });
    }
});

// 下载简历文件 - 增强版：支持ID和文件名两种方式查询，改进兼容性
// 注意：现在只从数据库读取简历，不再从文件系统获取
app.get('/api/download-resume/:fileName', async (req, res) => {
    try {
        const fileNameParam = req.params.fileName;
        console.log(`[${new Date().toISOString()}] 收到简历下载请求: ${fileNameParam}`);
        
        // 同时支持通过ID或文件名查询
        let fileName = fileNameParam;
        let isIdQuery = false;
        
        // 判断是否是数字ID请求
        if (/^\d+$/.test(fileNameParam)) {
            isIdQuery = true;
            console.log(`[${new Date().toISOString()}] 检测到可能是ID请求，尝试通过ID查询`);
        }
        
        // 设置超时处理 - 30秒超时防止请求挂起
        const timeout = setTimeout(() => {
            if (!res.headersSent) {
                console.error('简历下载请求超时');
                res.status(504).json({ error: '下载超时' });
            }
        }, 30000);
        
        // 安全验证文件名，防止路径遍历攻击
        if (!fileName || fileName.includes('..') || fileName.includes('/') || fileName.includes('\\') || fileName.trim() === '') {
            console.warn('检测到潜在的路径遍历攻击尝试:', fileName);
            clearTimeout(timeout);
            return res.status(400).json({ error: '无效的文件名' });
        }
        
        // 验证文件扩展名，确保只允许下载安全的文件类型
        // 在ID查询模式下跳过扩展名验证，因为ID没有扩展名
        if (!isIdQuery) {
            const allowedExtensions = ['.pdf', '.doc', '.docx', '.txt', '.rtf'];
            const fileExt = path.extname(fileName).toLowerCase();
            if (!allowedExtensions.includes(fileExt)) {
                clearTimeout(timeout);
                return res.status(400).json({ error: '不支持的文件类型' });
            }
        }
        
        let fileContent = null;
        let fileType = null;
        let dbRecordExists = false;
        let record = null; // 声明在外部作用域，以便后续使用
        
        // 只从数据库中读取文件，不再从文件系统获取
        if (useDatabase && pool) {
            console.log(`[${new Date().toISOString()}] 尝试从数据库读取简历文件: ${fileName}, ID查询模式: ${isIdQuery}`);
            try {
                // 根据查询类型构建SQL和参数
                let query, params;
                if (isIdQuery) {
                    // 通过ID查询 - 移除不存在的originalResumeName字段
                    query = 'SELECT fileContent, fileType, serverFileName FROM job_applications WHERE id = ? LIMIT 1';
                    params = [fileNameParam];
                } else {
                    // 通过文件名查询 - 移除不存在的originalResumeName字段
                    query = 'SELECT fileContent, fileType, serverFileName FROM job_applications WHERE serverFileName = ? LIMIT 1';
                    params = [fileName];
                }
                
                // 执行查询
                const [rows] = await pool.execute(query, params);
                console.log(`[${new Date().toISOString()}] 数据库查询执行完成，找到记录数: ${rows?.length || 0}`);
                
                if (rows && rows.length > 0) {
                    console.log('数据库中存在该文件名的记录');
                    record = rows[0]; // 使用外部作用域的变量
                    dbRecordExists = true; // 设置记录存在标记
                    
                    // 检查fileContent是否存在
                    if (record.fileContent) {
                        console.log('fileContent字段存在，开始处理...');
                        
                        // 保存原始fileContent类型信息
                        const originalType = typeof record.fileContent;
                        console.log(`原始fileContent类型: ${originalType}, 构造函数: ${record.fileContent.constructor.name}`);
                        
                        // 直接设置fileType
                        fileType = record.fileType || 'application/octet-stream';
                        console.log(`文件类型: ${fileType}, 服务器文件名: ${record.serverFileName || '未知'}`);
                        
                        // 增强版文件内容处理逻辑，支持多种数据格式
                        try {
                            console.log(`[${new Date().toISOString()}] 原始fileContent类型: ${originalType}, 构造函数: ${record.fileContent.constructor.name}`);
                            
                            // 获取原始内容的字符串表示（用于调试）
                            let contentPreview = '';
                            if (typeof record.fileContent === 'string' && record.fileContent.length > 0) {
                                contentPreview = record.fileContent.substring(0, 50) + (record.fileContent.length > 50 ? '...' : '');
                                console.log(`[${new Date().toISOString()}] 文件内容预览: ${contentPreview}`);
                            }
                            
                            // 优先判断是否看起来像Base64编码的字符串
                            if (typeof record.fileContent === 'string') {
                                // 检查是否符合Base64格式
                                const trimmedContent = record.fileContent.trim();
                                const isBase64 = /^[A-Za-z0-9+/=]+$/.test(trimmedContent) && 
                                               (trimmedContent.length % 4 === 0);
                                
                                console.log(`[${new Date().toISOString()}] 字符串内容长度: ${record.fileContent.length}, 是否可能是Base64: ${isBase64}`);
                                
                                // 尝试Base64解码
                                try {
                                    fileContent = Buffer.from(record.fileContent, 'base64');
                                    console.log(`[${new Date().toISOString()}] 尝试Base64解码成功，Buffer大小: ${fileContent.length} 字节`);
                                } catch (base64Error) {
                                    console.error(`[${new Date().toISOString()}] Base64解码失败: ${base64Error.message}`);
                                    // 回退：直接使用UTF-8编码
                                    fileContent = Buffer.from(record.fileContent, 'utf8');
                                    console.log(`[${new Date().toISOString()}] 使用UTF-8编码转换，Buffer大小: ${fileContent.length} 字节`);
                                }
                            }
                            // 已是Buffer类型，直接使用
                            else if (Buffer.isBuffer(record.fileContent)) {
                                fileContent = record.fileContent;
                                console.log(`[${new Date().toISOString()}] 已是Buffer类型，直接使用，大小: ${fileContent.length} 字节`);
                            }
                            // Uint8Array或ArrayBuffer
                            else if (record.fileContent instanceof Uint8Array || 
                                     record.fileContent instanceof ArrayBuffer) {
                                fileContent = Buffer.from(record.fileContent);
                                console.log(`[${new Date().toISOString()}] Uint8Array/ArrayBuffer转换为Buffer，大小: ${fileContent.length} 字节`);
                            }
                            // 对象类型，尝试获取其raw属性（某些数据库驱动可能使用这种格式）
                            else if (typeof record.fileContent === 'object' && record.fileContent !== null) {
                                console.log(`[${new Date().toISOString()}] 对象类型内容，尝试查找raw属性`);
                                
                                // 检查是否有raw或buffer属性
                                if (record.fileContent.raw) {
                                    fileContent = Buffer.from(record.fileContent.raw);
                                    console.log(`[${new Date().toISOString()}] 从raw属性获取Buffer，大小: ${fileContent.length} 字节`);
                                } else if (record.fileContent.buffer) {
                                    fileContent = Buffer.from(record.fileContent.buffer);
                                    console.log(`[${new Date().toISOString()}] 从buffer属性获取Buffer，大小: ${fileContent.length} 字节`);
                                } else {
                                    // 最后尝试字符串转换
                                    console.log(`[${new Date().toISOString()}] 对象没有raw/buffer属性，尝试字符串转换`);
                                    fileContent = Buffer.from(String(record.fileContent));
                                    console.log(`[${new Date().toISOString()}] 对象转换为Buffer，大小: ${fileContent.length} 字节`);
                                }
                            }
                            // 其他类型，尝试基本转换
                            else {
                                console.log(`[${new Date().toISOString()}] 其他类型内容，尝试基本转换`);
                                fileContent = Buffer.from(String(record.fileContent));
                                console.log(`[${new Date().toISOString()}] 基本类型转换为Buffer，大小: ${fileContent.length} 字节`);
                            }
                            
                            // 验证转换后的Buffer
                            if (fileContent && fileContent.length > 0) {
                                console.log(`成功准备文件内容，大小: ${fileContent.length} 字节`);
                            } else {
                                console.warn('转换后的文件内容为空或无效');
                                fileContent = null;
                            }
                        } catch (convertError) {
                            console.error('转换文件内容出错:', convertError);
                            // 即使转换失败，我们也尝试提供原始内容的信息
                            console.error('转换错误详情:', { 
                                originalValue: String(record.fileContent).substring(0, 100) + '...',
                                errorMessage: convertError.message 
                            });
                            fileContent = null;
                        }
                    } else {
                        console.warn('数据库记录存在但fileContent字段为空');
                    }
                } else {
                    console.log('数据库中不存在该文件名的记录');
                }
            } catch (dbError) {
                console.error('数据库查询出错:', dbError);
                console.error('数据库错误详情:', dbError.message);
            }
        } else {
            console.log('未使用数据库或数据库连接池不可用');
        }
        
        // 如果没有找到有效的文件内容
        if (!fileContent || !Buffer.isBuffer(fileContent) || fileContent.length === 0) {
            // 根据不同情况返回更具体的错误信息
            if (dbRecordExists) {
                // 增强的错误处理和日志记录
                const recordInfo = {
                    id: fileName,
                    serverFileName: record?.serverFileName || '未找到',
                    hasFileContent: record?.fileContent ? true : false,
                    fileContentSize: record?.fileContent ? (Buffer.isBuffer(record.fileContent) ? record.fileContent.length : String(record.fileContent).length) : 0,
                    fileExistsInFS: false
                };
                
                console.warn(`数据库记录存在但无法找到有效文件内容: ${JSON.stringify(recordInfo)}`);
                clearTimeout(timeout);
                
                // 返回更详细的错误信息，帮助调试
                return res.status(404).json({
                    error: '简历文件记录存在但文件内容丢失',
                    details: {
                        recordId: fileName,
                        serverFileName: record?.serverFileName || '未找到',
                        message: '简历文件可能已被删除或上传过程中出现问题'
                    }
                });
            } else {
                console.warn('未能找到任何匹配的文件记录:', fileName);
                clearTimeout(timeout);
                return res.status(404).json({ error: '简历文件不存在' });
            }
        }
        
        // 确定使用的文件名
        let downloadFileName = fileName;
        if (record && record.serverFileName) {
            downloadFileName = record.serverFileName;
            console.log(`[${new Date().toISOString()}] 使用服务器文件名: ${downloadFileName}`);
        }
        
        // 确保文件名有扩展名
        const ext = path.extname(downloadFileName).toLowerCase() || '.bin';
        if (!downloadFileName.includes('.')) {
            downloadFileName = `${downloadFileName}${ext}`;
        }
        
        // 设置通用响应头
        res.setHeader('Content-Type', fileType || 'application/octet-stream');
        res.setHeader('Content-Disposition', `attachment; filename="${encodeURIComponent(downloadFileName)}"`);
        res.setHeader('X-Content-Type-Options', 'nosniff'); // 防止MIME类型嗅探
        res.setHeader('Accept-Ranges', 'bytes'); // 支持范围请求
        res.setHeader('Cache-Control', 'no-store'); // 不缓存下载文件
        res.setHeader('Connection', 'keep-alive'); // 保持连接活跃
        
        // 处理文件传输
        try {
            if (fileContent && Buffer.isBuffer(fileContent) && fileContent.length > 0) {
                console.log(`[${new Date().toISOString()}] 准备发送数据库中的文件内容`);
                
                // 确保设置正确的内容长度
                const contentLength = fileContent.length;
                res.setHeader('Content-Length', contentLength);
                
                console.log(`[${new Date().toISOString()}] 准备发送Buffer内容，大小: ${contentLength} 字节`);
                
                // 监听响应相关事件
                res.on('finish', () => {
                    clearTimeout(timeout);
                    console.log(`[${new Date().toISOString()}] 文件下载完成: ${fileName}, 大小: ${contentLength} 字节`);
                });
                
                res.on('error', (err) => {
                    console.error(`[${new Date().toISOString()}] 响应错误:`, err);
                    clearTimeout(timeout);
                });
                
                // 简化发送逻辑：直接使用res.end()发送整个Buffer
                // Express会自动处理流控和分块传输
                res.end(fileContent);
            } else {
                // 如果没有找到有效的文件内容
                console.warn('无法发送文件：没有找到有效的文件内容');
                clearTimeout(timeout);
                if (!res.headersSent) {
                    res.status(404).json({ 
                        error: '简历文件内容无效或已损坏',
                        details: {
                            hasContent: !!fileContent,
                            isBuffer: fileContent ? Buffer.isBuffer(fileContent) : false,
                            contentLength: fileContent ? fileContent.length : 0
                        }
                    });
                }
            }
        } catch (sendError) {
            console.error('发送文件内容时出错:', sendError);
            console.error('错误栈:', sendError.stack);
            clearTimeout(timeout);
            if (!res.headersSent) {
                res.status(500).json({ 
                    error: '发送文件失败',
                    message: sendError.message 
                });
            }
        }
    } catch (error) {
        console.error('下载简历失败:', error);
        if (!res.headersSent) {
            res.status(500).json({ error: '下载简历失败' });
        }
    }
});

// 发送消息到飞书机器人 - 使用简化的格式并添加重试机制
function sendToFeishu(title, content, timeout = 5000) {
    // 输入验证，防止注入攻击
    if (typeof title !== 'string' || typeof content !== 'string') {
        console.error('飞书消息参数类型错误');
        return Promise.resolve({ success: false, error: '参数类型错误' });
    }
    
    // 限制消息长度，防止过长消息
    const MAX_TITLE_LENGTH = 50;
    const MAX_CONTENT_LENGTH = 1000;
    const safeTitle = title.substring(0, MAX_TITLE_LENGTH);
    const safeContent = content.substring(0, MAX_CONTENT_LENGTH);
    
    // 最大重试次数
    const MAX_RETRIES = 1;
    // 当前重试次数
    let retries = 0;
    
    // 重试延迟时间（毫秒）
    const getRetryDelay = (attempt) => Math.pow(2, attempt) * 1000 + Math.random() * 500; // 指数退避 + 随机抖动
    
    // 内部发送函数
    const sendWithRetry = () => {
        return new Promise((resolve) => {
            if (!FEISHU_WEBHOOK_URL) {
                console.warn('⚠️ 未配置飞书webhook URL，跳过发送');
                resolve({ success: false, error: '飞书webhook URL未配置' });
                return;
            }
        
            try {
                console.log(`准备发送消息到飞书 (尝试 ${retries + 1}/${MAX_RETRIES + 1})`);
                
                // 创建简化的消息内容，确保格式正确
                const messageText = `${safeTitle}\n${safeContent}`.replace(/[\r\n]+/g, '\n');
                
                // 使用最简单的成功格式
                const data = JSON.stringify({
                    msg_type: 'text',
                    content: {
                        text: messageText
                    }
                });
        
                console.log('准备发送到飞书的数据:', data.length, '字符');
                console.log('消息预览:', messageText.substring(0, 100) + '...');
        
                const options = {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    timeout: timeout // 添加请求超时
                };
        
                const req = https.request(FEISHU_WEBHOOK_URL, options, (res) => {
                    let responseData = '';
                    
                    res.on('data', (chunk) => {
                        responseData += chunk;
                    });
                    
                    res.on('end', () => {
                        console.log(`飞书响应状态码: ${res.statusCode}`);
                        console.log(`飞书响应内容: ${responseData}`);
                        
                        try {
                            // 尝试解析响应JSON
                            const responseJson = JSON.parse(responseData);
                            
                            // 检查是否是频率限制错误或其他可重试的错误
                            const shouldRetry = [
                                11232, // 频率限制
                                429,   // 太多请求
                                502,   // 网关错误
                                503,   // 服务不可用
                                504    // 网关超时
                            ].includes(responseJson.code || res.statusCode);
                            
                            if (shouldRetry) {
                                console.warn(`⚠️ 飞书API错误 (${responseJson.code || res.statusCode})，将在 ${Math.round(getRetryDelay(retries) / 1000)} 秒后重试`);
                                
                                // 如果未达到最大重试次数，进行重试
                                if (retries < MAX_RETRIES) {
                                    retries++;
                                    setTimeout(() => {
                                        sendWithRetry().then(resolve);
                                    }, getRetryDelay(retries - 1));
                                    return;
                                }
                                console.error('❌ 达到最大重试次数，发送失败');
                                resolve({ success: false, error: '达到最大重试次数，发送失败', response: responseData });
                                return;
                            }
                            
                            // 检查是否成功（支持多种成功标识）
                            const isSuccess = 
                                res.statusCode >= 200 && res.statusCode < 300 && 
                                (responseJson.code === 0 || 
                                 responseJson.StatusCode === 0 || 
                                 responseJson.ok === true ||
                                 responseJson.msg === 'success' ||
                                 responseJson.StatusMessage === 'success');
                            
                            if (isSuccess) {
                                console.log('✅ 消息已成功发送到飞书');
                                resolve({ success: true, data: responseData });
                            } else {
                                const errorMsg = responseJson.msg || 
                                                responseJson.StatusMessage || 
                                                responseJson.error || 
                                                '未知错误';
                                console.error('❌ 发送消息到飞书失败:', errorMsg);
                                resolve({ 
                                    success: false, 
                                    error: `发送失败: ${errorMsg}`, 
                                    response: responseData,
                                    code: responseJson.code || res.statusCode
                                });
                            }
                        } catch (e) {
                            console.log('响应不是有效的JSON，基于HTTP状态码判断');
                            // 即使响应不是JSON，如果HTTP状态码是2xx，也认为成功
                            if (res.statusCode >= 200 && res.statusCode < 300) {
                                console.log('✅ 基于HTTP状态码，消息发送成功');
                                resolve({ success: true, data: responseData });
                            } else {
                                console.error('❌ 发送消息到飞书失败，HTTP状态码错误:', res.statusCode);
                                resolve({ 
                                    success: false, 
                                    error: `HTTP错误 ${res.statusCode}`, 
                                    response: responseData
                                });
                            }
                        }
                    });
                });
                
                // 添加超时处理
                req.on('timeout', () => {
                    console.warn(`⚠️ 请求超时 (${timeout}ms)`);
                    req.destroy();
                    
                    // 超时也可以重试
                    if (retries < MAX_RETRIES) {
                        retries++;
                        console.log(`将在 ${Math.round(getRetryDelay(retries - 1) / 1000)} 秒后重试`);
                        setTimeout(() => {
                            sendWithRetry().then(resolve);
                        }, getRetryDelay(retries - 1));
                    } else {
                        resolve({ success: false, error: '请求超时，达到最大重试次数' });
                    }
                });
                
                // 添加错误处理
                req.on('error', (error) => {
                    console.error(`❌ 请求发生错误:`, error);
                    
                    // 网络错误可以重试
                    if (retries < MAX_RETRIES) {
                        retries++;
                        console.log(`将在 ${Math.round(getRetryDelay(retries - 1) / 1000)} 秒后重试`);
                        setTimeout(() => {
                            sendWithRetry().then(resolve);
                        }, getRetryDelay(retries - 1));
                    } else {
                        resolve({ 
                            success: false, 
                            error: `网络错误: ${error.message || '未知错误'}`
                        });
                    }
                });
                
                req.on('error', (error) => {
                    console.error('❌ 发送请求到飞书失败:', error);
                    
                    // 网络错误也可以重试
                    if (retries < MAX_RETRIES) {
                        retries++;
                        console.warn(`⚠️ 网络错误，将在 ${Math.round(getRetryDelay(retries) / 1000)} 秒后重试`);
                        setTimeout(() => {
                            sendWithRetry().then(resolve);
                        }, getRetryDelay(retries - 1));
                        return;
                    }
                    
                    resolve({ success: false, error: error.message });
                });
                
                req.write(data);
                req.end();
            } catch (error) {
                console.error('❌ 发送到飞书过程中发生异常:', error);
                resolve({ success: false, error: error.message });
            }
        });
    };
    
    // 开始发送
    return sendWithRetry();
}

// 启动服务器
async function startServer() {
    // 初始化数据库
    await initDatabase();
    
    // 配置静态文件服务，使前端可以访问公共资源
    // 从backend目录向上一级，然后访问frontend/public目录
    const path = require('path');
    
    // 配置后端public目录的静态文件服务，优先级高于前端
    const backendPublicPath = path.join(__dirname, 'public');
    app.use('/public', express.static(backendPublicPath));
    console.log(`后端静态文件服务已配置，目录: ${backendPublicPath}`);
    
    const publicPath = path.join(__dirname, '..', 'frontend', 'public');
    app.use('/public', express.static(publicPath));
    console.log(`前端静态文件服务已配置，目录: ${publicPath}`);
    
    // 尝试启动服务器，如果端口被占用则尝试其他端口
    function tryListen(port, maxRetries = 5) {
        // 创建服务器实例但不立即启动
        const server = require('http').createServer(app);
        
        server.listen(port, () => {
            console.log(`服务器运行在 http://localhost:${port}`);
        }).on('error', (err) => {
            // 处理端口占用错误
            if (err.code === 'EADDRINUSE') {
                console.log(`端口 ${port} 已被占用，${maxRetries > 0 ? `尝试使用端口 ${port + 1}` : '请手动指定其他端口'}`);
                server.close();
                
                // 如果还有重试次数，尝试下一个端口
                if (maxRetries > 0) {
                    setTimeout(() => tryListen(port + 1, maxRetries - 1), 100);
                } else {
                    console.error('无法找到可用端口，请尝试手动指定其他端口或关闭占用端口的进程');
                    process.exit(1);
                }
            } else {
                console.error('服务器启动失败:', err);
                process.exit(1);
            }
        });
    }
    
    // 开始尝试监听端口
    tryListen(parseInt(PORT));
}

// 启动服务器
startServer().catch(err => {
    console.error('服务器启动失败:', err);
    process.exit(1);
});